summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorHyungKyu Song <hk76.song@samsung.com>2013-02-16 00:14:42 +0900
committerHyungKyu Song <hk76.song@samsung.com>2013-02-16 00:14:42 +0900
commit715f9ce62a12d128754d2cf47f90a024b537e320 (patch)
tree57fb94c81055a31938bea831641092152a03089f /ext
parentdfa84b358c7cdf0535eba1fead62fc4122cc56e6 (diff)
downloadgst-plugins-good0.10-tizen_2.0.tar.gz
gst-plugins-good0.10-tizen_2.0.tar.bz2
gst-plugins-good0.10-tizen_2.0.zip
Diffstat (limited to 'ext')
-rw-r--r--ext/Makefile.am180
-rw-r--r--ext/Makefile.in919
-rw-r--r--ext/aalib/Makefile.am9
-rw-r--r--ext/aalib/Makefile.in805
-rw-r--r--ext/aalib/gstaasink.c587
-rw-r--r--ext/aalib/gstaasink.h79
-rw-r--r--ext/annodex/Makefile.am19
-rw-r--r--ext/annodex/Makefile.in863
-rw-r--r--ext/annodex/gstannodex.c167
-rw-r--r--ext/annodex/gstannodex.h34
-rw-r--r--ext/annodex/gstcmmldec.c708
-rw-r--r--ext/annodex/gstcmmldec.h98
-rw-r--r--ext/annodex/gstcmmlenc.c631
-rw-r--r--ext/annodex/gstcmmlenc.h79
-rw-r--r--ext/annodex/gstcmmlparser.c648
-rw-r--r--ext/annodex/gstcmmlparser.h92
-rw-r--r--ext/annodex/gstcmmltag.c579
-rw-r--r--ext/annodex/gstcmmltag.h133
-rw-r--r--ext/annodex/gstcmmlutils.c388
-rw-r--r--ext/annodex/gstcmmlutils.h53
-rw-r--r--ext/cairo/Makefile.am45
-rw-r--r--ext/cairo/Makefile.in942
-rw-r--r--ext/cairo/gstcairo-marshal.list2
-rw-r--r--ext/cairo/gstcairo.c59
-rw-r--r--ext/cairo/gstcairooverlay.c250
-rw-r--r--ext/cairo/gstcairooverlay.h63
-rw-r--r--ext/cairo/gstcairorender.c383
-rw-r--r--ext/cairo/gstcairorender.h63
-rw-r--r--ext/cairo/gsttextoverlay.c1042
-rw-r--r--ext/cairo/gsttextoverlay.h90
-rw-r--r--ext/cairo/gsttimeoverlay.c316
-rw-r--r--ext/cairo/gsttimeoverlay.h59
-rw-r--r--ext/dv/Makefile.am20
-rw-r--r--ext/dv/Makefile.in890
-rw-r--r--ext/dv/NOTES13
-rw-r--r--ext/dv/gstdv.c48
-rw-r--r--ext/dv/gstdvdec.c617
-rw-r--r--ext/dv/gstdvdec.h95
-rw-r--r--ext/dv/gstdvdemux.c1908
-rw-r--r--ext/dv/gstdvdemux.h98
-rw-r--r--ext/dv/gstsmptetimecode.c240
-rw-r--r--ext/dv/gstsmptetimecode.h70
-rw-r--r--ext/dv/smpte_test.c81
-rw-r--r--ext/esd/Makefile.am14
-rw-r--r--ext/esd/Makefile.in821
-rw-r--r--ext/esd/esdmon.h77
-rw-r--r--ext/esd/esdsink.c468
-rw-r--r--ext/esd/esdsink.h64
-rw-r--r--ext/esd/gstesd.c60
-rw-r--r--ext/flac/Makefile.am13
-rw-r--r--ext/flac/Makefile.in838
-rw-r--r--ext/flac/gstflac.c60
-rw-r--r--ext/flac/gstflacdec.c2176
-rw-r--r--ext/flac/gstflacdec.h101
-rw-r--r--ext/flac/gstflacenc.c1399
-rw-r--r--ext/flac/gstflacenc.h79
-rw-r--r--ext/flac/gstflactag.c490
-rw-r--r--ext/flac/gstflactag.h78
-rw-r--r--ext/gconf/Makefile.am27
-rw-r--r--ext/gconf/Makefile.in888
-rw-r--r--ext/gconf/gstgconf.c304
-rw-r--r--ext/gconf/gstgconf.h66
-rw-r--r--ext/gconf/gstgconfaudiosink.c310
-rw-r--r--ext/gconf/gstgconfaudiosink.h62
-rw-r--r--ext/gconf/gstgconfaudiosrc.c210
-rw-r--r--ext/gconf/gstgconfaudiosrc.h57
-rw-r--r--ext/gconf/gstgconfelements.c59
-rw-r--r--ext/gconf/gstgconfelements.h28
-rw-r--r--ext/gconf/gstgconfvideosink.c210
-rw-r--r--ext/gconf/gstgconfvideosink.h64
-rw-r--r--ext/gconf/gstgconfvideosrc.c209
-rw-r--r--ext/gconf/gstgconfvideosrc.h58
-rw-r--r--ext/gconf/gstswitchsink.c269
-rw-r--r--ext/gconf/gstswitchsink.h62
-rw-r--r--ext/gconf/gstswitchsrc.c261
-rw-r--r--ext/gconf/gstswitchsrc.h57
-rw-r--r--ext/gdk_pixbuf/Makefile.am19
-rw-r--r--ext/gdk_pixbuf/Makefile.in837
-rw-r--r--ext/gdk_pixbuf/gstgdkanimation.h117
-rw-r--r--ext/gdk_pixbuf/gstgdkpixbuf.c558
-rw-r--r--ext/gdk_pixbuf/gstgdkpixbuf.h70
-rw-r--r--ext/gdk_pixbuf/gstgdkpixbufsink.c426
-rw-r--r--ext/gdk_pixbuf/gstgdkpixbufsink.h75
-rw-r--r--ext/gdk_pixbuf/pixbufscale.c483
-rw-r--r--ext/gdk_pixbuf/pixbufscale.h84
-rw-r--r--ext/hal/Makefile.am18
-rw-r--r--ext/hal/Makefile.in843
-rw-r--r--ext/hal/gsthalaudiosink.c250
-rw-r--r--ext/hal/gsthalaudiosink.h58
-rw-r--r--ext/hal/gsthalaudiosrc.c251
-rw-r--r--ext/hal/gsthalaudiosrc.h52
-rw-r--r--ext/hal/gsthalelements.c54
-rw-r--r--ext/hal/gsthalelements.h29
-rw-r--r--ext/hal/hal.c397
-rw-r--r--ext/hal/hal.h48
-rw-r--r--ext/jack/Makefile.am10
-rw-r--r--ext/jack/Makefile.in840
-rw-r--r--ext/jack/gstjack.c97
-rw-r--r--ext/jack/gstjack.h55
-rw-r--r--ext/jack/gstjackaudioclient.c527
-rw-r--r--ext/jack/gstjackaudioclient.h59
-rw-r--r--ext/jack/gstjackaudiosink.c903
-rw-r--r--ext/jack/gstjackaudiosink.h80
-rw-r--r--ext/jack/gstjackaudiosrc.c924
-rw-r--r--ext/jack/gstjackaudiosrc.h98
-rw-r--r--ext/jack/gstjackringbuffer.h88
-rw-r--r--ext/jack/gstjackutil.c114
-rw-r--r--ext/jack/gstjackutil.h30
-rw-r--r--ext/jpeg/Makefile.am21
-rw-r--r--ext/jpeg/Makefile.in863
-rw-r--r--ext/jpeg/README20
-rw-r--r--ext/jpeg/gstjpeg.c77
-rw-r--r--ext/jpeg/gstjpeg.h35
-rw-r--r--ext/jpeg/gstjpegdec.c1873
-rw-r--r--ext/jpeg/gstjpegdec.h150
-rw-r--r--ext/jpeg/gstjpegenc.c744
-rw-r--r--ext/jpeg/gstjpegenc.h109
-rw-r--r--ext/jpeg/gstsmokedec.c332
-rw-r--r--ext/jpeg/gstsmokedec.h75
-rw-r--r--ext/jpeg/gstsmokeenc.c509
-rw-r--r--ext/jpeg/gstsmokeenc.h75
-rw-r--r--ext/jpeg/smokecodec.c709
-rw-r--r--ext/jpeg/smokecodec.h119
-rw-r--r--ext/jpeg/smokeformat.h46
-rw-r--r--ext/libcaca/Makefile.am16
-rw-r--r--ext/libcaca/Makefile.in814
-rw-r--r--ext/libcaca/gstcacasink.c426
-rw-r--r--ext/libcaca/gstcacasink.h72
-rw-r--r--ext/libpng/Makefile.am10
-rw-r--r--ext/libpng/Makefile.in824
-rw-r--r--ext/libpng/gstpng.c47
-rw-r--r--ext/libpng/gstpngdec.c898
-rw-r--r--ext/libpng/gstpngdec.h84
-rw-r--r--ext/libpng/gstpngenc.c432
-rw-r--r--ext/libpng/gstpngenc.h75
-rw-r--r--ext/pulse/Makefile.am29
-rw-r--r--ext/pulse/Makefile.in895
-rw-r--r--ext/pulse/plugin.c70
-rw-r--r--ext/pulse/pulseaudiosink.c938
-rw-r--r--ext/pulse/pulsemixer.c282
-rw-r--r--ext/pulse/pulsemixer.h68
-rw-r--r--ext/pulse/pulsemixerctrl.c640
-rw-r--r--ext/pulse/pulsemixerctrl.h175
-rw-r--r--ext/pulse/pulsemixertrack.c67
-rw-r--r--ext/pulse/pulsemixertrack.h60
-rw-r--r--ext/pulse/pulseprobe.c416
-rw-r--r--ext/pulse/pulseprobe.h127
-rw-r--r--ext/pulse/pulsesink.c3024
-rw-r--r--ext/pulse/pulsesink.h182
-rw-r--r--ext/pulse/pulsesrc.c1750
-rw-r--r--ext/pulse/pulsesrc.h102
-rw-r--r--ext/pulse/pulseutil.c337
-rw-r--r--ext/pulse/pulseutil.h52
-rw-r--r--ext/raw1394/Makefile.am29
-rw-r--r--ext/raw1394/Makefile.in864
-rw-r--r--ext/raw1394/gst1394.c51
-rw-r--r--ext/raw1394/gst1394clock.c154
-rw-r--r--ext/raw1394/gst1394clock.h77
-rw-r--r--ext/raw1394/gst1394probe.c140
-rw-r--r--ext/raw1394/gst1394probe.h32
-rw-r--r--ext/raw1394/gstdv1394src.c1134
-rw-r--r--ext/raw1394/gstdv1394src.h101
-rw-r--r--ext/raw1394/gsthdv1394src.c844
-rw-r--r--ext/raw1394/gsthdv1394src.h85
-rw-r--r--ext/shout2/Makefile.am9
-rw-r--r--ext/shout2/Makefile.in805
-rw-r--r--ext/shout2/gstshout2.c852
-rw-r--r--ext/shout2/gstshout2.h97
-rw-r--r--ext/soup/Makefile.am10
-rw-r--r--ext/soup/Makefile.in824
-rw-r--r--ext/soup/gstsoup.c47
-rw-r--r--ext/soup/gstsouphttpclientsink.c765
-rw-r--r--ext/soup/gstsouphttpclientsink.h81
-rw-r--r--ext/soup/gstsouphttpsrc.c1676
-rw-r--r--ext/soup/gstsouphttpsrc.h107
-rw-r--r--ext/speex/Makefile.am18
-rw-r--r--ext/speex/Makefile.in834
-rw-r--r--ext/speex/gstspeex.c49
-rw-r--r--ext/speex/gstspeexdec.c549
-rw-r--r--ext/speex/gstspeexdec.h80
-rw-r--r--ext/speex/gstspeexenc.c850
-rw-r--r--ext/speex/gstspeexenc.h102
-rw-r--r--ext/taglib/Makefile.am19
-rw-r--r--ext/taglib/Makefile.in872
-rw-r--r--ext/taglib/gstapev2mux.cc373
-rw-r--r--ext/taglib/gstapev2mux.h55
-rw-r--r--ext/taglib/gstid3v2mux.cc775
-rw-r--r--ext/taglib/gstid3v2mux.h54
-rw-r--r--ext/taglib/gsttaglibmux.c402
-rw-r--r--ext/taglib/gsttaglibmux.h71
-rw-r--r--ext/wavpack/Makefile.am24
-rw-r--r--ext/wavpack/Makefile.in868
-rw-r--r--ext/wavpack/gstwavpack.c56
-rw-r--r--ext/wavpack/gstwavpackcommon.c282
-rw-r--r--ext/wavpack/gstwavpackcommon.h75
-rw-r--r--ext/wavpack/gstwavpackdec.c512
-rw-r--r--ext/wavpack/gstwavpackdec.h80
-rw-r--r--ext/wavpack/gstwavpackenc.c1049
-rw-r--r--ext/wavpack/gstwavpackenc.h104
-rw-r--r--ext/wavpack/gstwavpackparse.c1344
-rw-r--r--ext/wavpack/gstwavpackparse.h97
-rw-r--r--ext/wavpack/gstwavpackstreamreader.c124
-rw-r--r--ext/wavpack/gstwavpackstreamreader.h36
203 files changed, 70105 insertions, 0 deletions
diff --git a/ext/Makefile.am b/ext/Makefile.am
new file mode 100644
index 0000000..409408e
--- /dev/null
+++ b/ext/Makefile.am
@@ -0,0 +1,180 @@
+if USE_AALIB
+AALIB_DIR = aalib
+else
+AALIB_DIR =
+endif
+
+if USE_ANNODEX
+ANNODEX_DIR = annodex
+else
+ANNODEX_DIR =
+endif
+
+if USE_CAIRO
+CAIRO_DIR = cairo
+else
+CAIRO_DIR =
+endif
+
+if USE_ESD
+ESD_DIR = esd
+else
+ESD_DIR =
+endif
+
+if USE_FLAC
+FLAC_DIR = flac
+else
+FLAC_DIR =
+endif
+
+if USE_GCONF
+GCONF_DIR = gconf
+else
+GCONF_DIR =
+endif
+
+if USE_GDK_PIXBUF
+GDK_PIXBUF_DIR = gdk_pixbuf
+else
+GDK_PIXBUF_DIR =
+endif
+
+if USE_HAL
+HAL_DIR = hal
+else
+HAL_DIR =
+endif
+
+if USE_JACK
+JACK_DIR=jack
+else
+JACK_DIR=
+endif
+
+if USE_JPEG
+JPEG_DIR = jpeg
+else
+JPEG_DIR =
+endif
+
+if USE_LIBCACA
+LIBCACA_DIR = libcaca
+else
+LIBCACA_DIR =
+endif
+
+if USE_LIBDV
+LIBDV_DIR = dv
+else
+LIBDV_DIR =
+endif
+
+# if USE_LIBMNG
+# LIBMNG_DIR = libmng
+# else
+LIBMNG_DIR =
+# endif
+
+if USE_LIBPNG
+LIBPNG_DIR = libpng
+else
+LIBPNG_DIR =
+endif
+
+# if USE_MIKMOD
+# MIKMOD_DIR = mikmod
+# else
+MIKMOD_DIR =
+# endif
+
+if USE_DV1394
+DV1394_DIR = raw1394
+else
+DV1394_DIR =
+endif
+
+if USE_PULSE
+PULSE_DIR = pulse
+else
+PULSE_DIR =
+endif
+
+
+if USE_SHOUT2
+SHOUT2_DIR = shout2
+else
+SHOUT2_DIR =
+endif
+
+if USE_SOUP
+SOUP_DIR=soup
+else
+SOUP_DIR=
+endif
+
+if USE_SPEEX
+SPEEX_DIR = speex
+else
+SPEEX_DIR =
+endif
+
+if USE_TAGLIB
+TAGLIB_DIR = taglib
+else
+TAGLIB_DIR =
+endif
+
+if USE_WAVPACK
+WAVPACK_DIR=wavpack
+else
+WAVPACK_DIR=
+endif
+
+SUBDIRS = \
+ $(AALIB_DIR) \
+ $(ANNODEX_DIR) \
+ $(CAIRO_DIR) \
+ $(DV1394_DIR) \
+ $(ESD_DIR) \
+ $(FLAC_DIR) \
+ $(GCONF_DIR) \
+ $(GDK_PIXBUF_DIR) \
+ $(HAL_DIR) \
+ $(JACK_DIR) \
+ $(JPEG_DIR) \
+ $(LIBCACA_DIR) \
+ $(LIBDV_DIR) \
+ $(LIBMNG_DIR) \
+ $(LIBPNG_DIR) \
+ $(MIKMOD_DIR) \
+ $(PULSE_DIR) \
+ $(SHOUT2_DIR) \
+ $(SOUP_DIR) \
+ $(SPEEX_DIR) \
+ $(TAGLIB_DIR) \
+ $(WAVPACK_DIR)
+
+DIST_SUBDIRS = \
+ aalib \
+ annodex \
+ cairo \
+ dv \
+ esd \
+ flac \
+ gconf \
+ gdk_pixbuf \
+ hal \
+ jack \
+ jpeg \
+ libcaca \
+ libpng \
+ pulse \
+ raw1394 \
+ shout2 \
+ soup \
+ speex \
+ taglib \
+ wavpack
+
+include $(top_srcdir)/common/parallel-subdirs.mak
diff --git a/ext/Makefile.in b/ext/Makefile.in
new file mode 100644
index 0000000..ab5eeca
--- /dev/null
+++ b/ext/Makefile.in
@@ -0,0 +1,919 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# include this at the end of $MODULE/ext/Makefile.am to force make to
+# build subdirectories in parallel when make -jN is used. We will end up
+# descending into all subdirectories a second time, but only after the first
+# (parallel) run has finished, so it should go right through the second time.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(top_srcdir)/common/parallel-subdirs.mak
+subdir = ext
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@USE_AALIB_FALSE@AALIB_DIR =
+@USE_AALIB_TRUE@AALIB_DIR = aalib
+@USE_ANNODEX_FALSE@ANNODEX_DIR =
+@USE_ANNODEX_TRUE@ANNODEX_DIR = annodex
+@USE_CAIRO_FALSE@CAIRO_DIR =
+@USE_CAIRO_TRUE@CAIRO_DIR = cairo
+@USE_ESD_FALSE@ESD_DIR =
+@USE_ESD_TRUE@ESD_DIR = esd
+@USE_FLAC_FALSE@FLAC_DIR =
+@USE_FLAC_TRUE@FLAC_DIR = flac
+@USE_GCONF_FALSE@GCONF_DIR =
+@USE_GCONF_TRUE@GCONF_DIR = gconf
+@USE_GDK_PIXBUF_FALSE@GDK_PIXBUF_DIR =
+@USE_GDK_PIXBUF_TRUE@GDK_PIXBUF_DIR = gdk_pixbuf
+@USE_HAL_FALSE@HAL_DIR =
+@USE_HAL_TRUE@HAL_DIR = hal
+@USE_JACK_FALSE@JACK_DIR =
+@USE_JACK_TRUE@JACK_DIR = jack
+@USE_JPEG_FALSE@JPEG_DIR =
+@USE_JPEG_TRUE@JPEG_DIR = jpeg
+@USE_LIBCACA_FALSE@LIBCACA_DIR =
+@USE_LIBCACA_TRUE@LIBCACA_DIR = libcaca
+@USE_LIBDV_FALSE@LIBDV_DIR =
+@USE_LIBDV_TRUE@LIBDV_DIR = dv
+
+# if USE_LIBMNG
+# LIBMNG_DIR = libmng
+# else
+LIBMNG_DIR =
+@USE_LIBPNG_FALSE@LIBPNG_DIR =
+# endif
+@USE_LIBPNG_TRUE@LIBPNG_DIR = libpng
+
+# if USE_MIKMOD
+# MIKMOD_DIR = mikmod
+# else
+MIKMOD_DIR =
+@USE_DV1394_FALSE@DV1394_DIR =
+# endif
+@USE_DV1394_TRUE@DV1394_DIR = raw1394
+@USE_PULSE_FALSE@PULSE_DIR =
+@USE_PULSE_TRUE@PULSE_DIR = pulse
+@USE_SHOUT2_FALSE@SHOUT2_DIR =
+@USE_SHOUT2_TRUE@SHOUT2_DIR = shout2
+@USE_SOUP_FALSE@SOUP_DIR =
+@USE_SOUP_TRUE@SOUP_DIR = soup
+@USE_SPEEX_FALSE@SPEEX_DIR =
+@USE_SPEEX_TRUE@SPEEX_DIR = speex
+@USE_TAGLIB_FALSE@TAGLIB_DIR =
+@USE_TAGLIB_TRUE@TAGLIB_DIR = taglib
+@USE_WAVPACK_FALSE@WAVPACK_DIR =
+@USE_WAVPACK_TRUE@WAVPACK_DIR = wavpack
+SUBDIRS = \
+ $(AALIB_DIR) \
+ $(ANNODEX_DIR) \
+ $(CAIRO_DIR) \
+ $(DV1394_DIR) \
+ $(ESD_DIR) \
+ $(FLAC_DIR) \
+ $(GCONF_DIR) \
+ $(GDK_PIXBUF_DIR) \
+ $(HAL_DIR) \
+ $(JACK_DIR) \
+ $(JPEG_DIR) \
+ $(LIBCACA_DIR) \
+ $(LIBDV_DIR) \
+ $(LIBMNG_DIR) \
+ $(LIBPNG_DIR) \
+ $(MIKMOD_DIR) \
+ $(PULSE_DIR) \
+ $(SHOUT2_DIR) \
+ $(SOUP_DIR) \
+ $(SPEEX_DIR) \
+ $(TAGLIB_DIR) \
+ $(WAVPACK_DIR)
+
+DIST_SUBDIRS = \
+ aalib \
+ annodex \
+ cairo \
+ dv \
+ esd \
+ flac \
+ gconf \
+ gdk_pixbuf \
+ hal \
+ jack \
+ jpeg \
+ libcaca \
+ libpng \
+ pulse \
+ raw1394 \
+ shout2 \
+ soup \
+ speex \
+ taglib \
+ wavpack
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common/parallel-subdirs.mak $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+$(top_srcdir)/common/parallel-subdirs.mak:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+ install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am check check-am clean clean-generic clean-libtool \
+ ctags ctags-recursive distclean distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am
+
+
+.PHONY: independent-subdirs $(SUBDIRS)
+
+independent-subdirs: $(SUBDIRS)
+
+$(SUBDIRS):
+ $(MAKE) -C $@
+
+all-recursive: independent-subdirs
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/aalib/Makefile.am b/ext/aalib/Makefile.am
new file mode 100644
index 0000000..5820b24
--- /dev/null
+++ b/ext/aalib/Makefile.am
@@ -0,0 +1,9 @@
+plugin_LTLIBRARIES = libgstaasink.la
+
+libgstaasink_la_SOURCES = gstaasink.c
+libgstaasink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AALIB_CFLAGS)
+libgstaasink_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(AALIB_LIBS)
+libgstaasink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstaasink_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstaasink.h
diff --git a/ext/aalib/Makefile.in b/ext/aalib/Makefile.in
new file mode 100644
index 0000000..2e9e138
--- /dev/null
+++ b/ext/aalib/Makefile.in
@@ -0,0 +1,805 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/aalib
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstaasink_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libgstaasink_la_OBJECTS = libgstaasink_la-gstaasink.lo
+libgstaasink_la_OBJECTS = $(am_libgstaasink_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstaasink_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstaasink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstaasink_la_CFLAGS) $(CFLAGS) \
+ $(libgstaasink_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstaasink_la_SOURCES)
+DIST_SOURCES = $(libgstaasink_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstaasink.la
+libgstaasink_la_SOURCES = gstaasink.c
+libgstaasink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AALIB_CFLAGS)
+libgstaasink_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(AALIB_LIBS)
+libgstaasink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstaasink_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = gstaasink.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/aalib/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/aalib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstaasink.la: $(libgstaasink_la_OBJECTS) $(libgstaasink_la_DEPENDENCIES) $(EXTRA_libgstaasink_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstaasink_la_LINK) -rpath $(plugindir) $(libgstaasink_la_OBJECTS) $(libgstaasink_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstaasink_la-gstaasink.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstaasink_la-gstaasink.lo: gstaasink.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstaasink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstaasink_la_CFLAGS) $(CFLAGS) -MT libgstaasink_la-gstaasink.lo -MD -MP -MF $(DEPDIR)/libgstaasink_la-gstaasink.Tpo -c -o libgstaasink_la-gstaasink.lo `test -f 'gstaasink.c' || echo '$(srcdir)/'`gstaasink.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstaasink_la-gstaasink.Tpo $(DEPDIR)/libgstaasink_la-gstaasink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstaasink.c' object='libgstaasink_la-gstaasink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstaasink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstaasink_la_CFLAGS) $(CFLAGS) -c -o libgstaasink_la-gstaasink.lo `test -f 'gstaasink.c' || echo '$(srcdir)/'`gstaasink.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/aalib/gstaasink.c b/ext/aalib/gstaasink.c
new file mode 100644
index 0000000..2909dde
--- /dev/null
+++ b/ext/aalib/gstaasink.c
@@ -0,0 +1,587 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:element-aasink
+ * @see_also: #GstCACASink
+ *
+ * Displays video as b/w ascii art.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch filesrc location=test.avi ! decodebin ! ffmpegcolorspace ! aasink
+ * ]| This pipeline renders a video to ascii art into a separate window.
+ * |[
+ * gst-launch filesrc location=test.avi ! decodebin ! ffmpegcolorspace ! aasink driver=curses
+ * ]| This pipeline renders a video to ascii art into the current terminal.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <sys/time.h>
+
+#include "gstaasink.h"
+#include <gst/video/video.h>
+
+/* aasink signals and args */
+enum
+{
+ SIGNAL_FRAME_DISPLAYED,
+ SIGNAL_HAVE_SIZE,
+ LAST_SIGNAL
+};
+
+
+enum
+{
+ ARG_0,
+ ARG_WIDTH,
+ ARG_HEIGHT,
+ ARG_DRIVER,
+ ARG_DITHER,
+ ARG_BRIGHTNESS,
+ ARG_CONTRAST,
+ ARG_GAMMA,
+ ARG_INVERSION,
+ ARG_RANDOMVAL,
+ ARG_FRAMES_DISPLAYED,
+ ARG_FRAME_TIME
+};
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
+ );
+
+static void gst_aasink_base_init (gpointer g_class);
+static void gst_aasink_class_init (GstAASinkClass * klass);
+static void gst_aasink_init (GstAASink * aasink);
+
+static gboolean gst_aasink_setcaps (GstBaseSink * pad, GstCaps * caps);
+static void gst_aasink_get_times (GstBaseSink * sink, GstBuffer * buffer,
+ GstClockTime * start, GstClockTime * end);
+static GstFlowReturn gst_aasink_render (GstBaseSink * basesink,
+ GstBuffer * buffer);
+
+static void gst_aasink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_aasink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn gst_aasink_change_state (GstElement * element,
+ GstStateChange transition);
+
+static GstElementClass *parent_class = NULL;
+static guint gst_aasink_signals[LAST_SIGNAL] = { 0 };
+
+GType
+gst_aasink_get_type (void)
+{
+ static GType aasink_type = 0;
+
+ if (!aasink_type) {
+ static const GTypeInfo aasink_info = {
+ sizeof (GstAASinkClass),
+ gst_aasink_base_init,
+ NULL,
+ (GClassInitFunc) gst_aasink_class_init,
+ NULL,
+ NULL,
+ sizeof (GstAASink),
+ 0,
+ (GInstanceInitFunc) gst_aasink_init,
+ };
+
+ aasink_type =
+ g_type_register_static (GST_TYPE_BASE_SINK, "GstAASink", &aasink_info,
+ 0);
+ }
+ return aasink_type;
+}
+
+#define GST_TYPE_AADRIVERS (gst_aasink_drivers_get_type())
+static GType
+gst_aasink_drivers_get_type (void)
+{
+ static GType driver_type = 0;
+
+ if (!driver_type) {
+ GEnumValue *drivers;
+ const struct aa_driver *driver;
+ gint n_drivers;
+ gint i;
+
+ for (n_drivers = 0; aa_drivers[n_drivers]; n_drivers++) {
+ /* count number of drivers */
+ }
+
+ drivers = g_new0 (GEnumValue, n_drivers + 1);
+
+ for (i = 0; i < n_drivers; i++) {
+ driver = aa_drivers[i];
+ drivers[i].value = i;
+ drivers[i].value_name = g_strdup (driver->name);
+ drivers[i].value_nick = g_utf8_strdown (driver->shortname, -1);
+ }
+ drivers[i].value = 0;
+ drivers[i].value_name = NULL;
+ drivers[i].value_nick = NULL;
+
+ driver_type = g_enum_register_static ("GstAASinkDrivers", drivers);
+ }
+ return driver_type;
+}
+
+#define GST_TYPE_AADITHER (gst_aasink_dither_get_type())
+static GType
+gst_aasink_dither_get_type (void)
+{
+ static GType dither_type = 0;
+
+ if (!dither_type) {
+ GEnumValue *ditherers;
+ gint n_ditherers;
+ gint i;
+
+ for (n_ditherers = 0; aa_dithernames[n_ditherers]; n_ditherers++) {
+ /* count number of ditherers */
+ }
+
+ ditherers = g_new0 (GEnumValue, n_ditherers + 1);
+
+ for (i = 0; i < n_ditherers; i++) {
+ ditherers[i].value = i;
+ ditherers[i].value_name = g_strdup (aa_dithernames[i]);
+ ditherers[i].value_nick =
+ g_strdelimit (g_strdup (aa_dithernames[i]), " _", '-');
+ }
+ ditherers[i].value = 0;
+ ditherers[i].value_name = NULL;
+ ditherers[i].value_nick = NULL;
+
+ dither_type = g_enum_register_static ("GstAASinkDitherers", ditherers);
+ }
+ return dither_type;
+}
+
+static void
+gst_aasink_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &sink_template);
+ gst_element_class_set_details_simple (element_class, "ASCII art video sink",
+ "Sink/Video",
+ "An ASCII art videosink", "Wim Taymans <wim.taymans@chello.be>");
+}
+
+static void
+gst_aasink_class_init (GstAASinkClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstBaseSinkClass *gstbasesink_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstbasesink_class = (GstBaseSinkClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->set_property = gst_aasink_set_property;
+ gobject_class->get_property = gst_aasink_get_property;
+
+ /* FIXME: add long property descriptions */
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_WIDTH,
+ g_param_spec_int ("width", "width", "width", G_MININT, G_MAXINT, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HEIGHT,
+ g_param_spec_int ("height", "height", "height", G_MININT, G_MAXINT, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DRIVER,
+ g_param_spec_enum ("driver", "driver", "driver", GST_TYPE_AADRIVERS, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DITHER,
+ g_param_spec_enum ("dither", "dither", "dither", GST_TYPE_AADITHER, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BRIGHTNESS,
+ g_param_spec_int ("brightness", "brightness", "brightness", G_MININT,
+ G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CONTRAST,
+ g_param_spec_int ("contrast", "contrast", "contrast", G_MININT, G_MAXINT,
+ 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GAMMA,
+ g_param_spec_float ("gamma", "gamma", "gamma", 0.0, 5.0, 1.0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_INVERSION,
+ g_param_spec_boolean ("inversion", "inversion", "inversion", TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_RANDOMVAL,
+ g_param_spec_int ("randomval", "randomval", "randomval", G_MININT,
+ G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FRAMES_DISPLAYED,
+ g_param_spec_int ("frames-displayed", "frames displayed",
+ "frames displayed", G_MININT, G_MAXINT, 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FRAME_TIME,
+ g_param_spec_int ("frame-time", "frame time", "frame time", G_MININT,
+ G_MAXINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ gst_aasink_signals[SIGNAL_FRAME_DISPLAYED] =
+ g_signal_new ("frame-displayed", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAASinkClass, frame_displayed),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+ gst_aasink_signals[SIGNAL_HAVE_SIZE] =
+ g_signal_new ("have-size", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstAASinkClass, have_size), NULL, NULL,
+ gst_marshal_VOID__INT_INT, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
+
+ gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_aasink_change_state);
+
+ gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_aasink_setcaps);
+ gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_aasink_get_times);
+ gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_aasink_render);
+ gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_aasink_render);
+}
+
+static void
+gst_aasink_fixate (GstPad * pad, GstCaps * caps)
+{
+ GstStructure *structure;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ gst_structure_fixate_field_nearest_int (structure, "width", 320);
+ gst_structure_fixate_field_nearest_int (structure, "height", 240);
+ gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
+}
+
+static gboolean
+gst_aasink_setcaps (GstBaseSink * basesink, GstCaps * caps)
+{
+ GstAASink *aasink;
+ GstStructure *structure;
+
+ aasink = GST_AASINK (basesink);
+
+ structure = gst_caps_get_structure (caps, 0);
+ gst_structure_get_int (structure, "width", &aasink->width);
+ gst_structure_get_int (structure, "height", &aasink->height);
+
+ /* FIXME aasink->format is never set */
+ g_print ("%d %d\n", aasink->width, aasink->height);
+
+ GST_DEBUG ("aasink: setting %08lx (%" GST_FOURCC_FORMAT ")",
+ aasink->format, GST_FOURCC_ARGS (aasink->format));
+
+ g_signal_emit (G_OBJECT (aasink), gst_aasink_signals[SIGNAL_HAVE_SIZE], 0,
+ aasink->width, aasink->height);
+
+ return TRUE;
+}
+
+static void
+gst_aasink_init (GstAASink * aasink)
+{
+ GstPad *pad;
+
+ pad = GST_BASE_SINK_PAD (aasink);
+ gst_pad_set_fixatecaps_function (pad, gst_aasink_fixate);
+
+ memcpy (&aasink->ascii_surf, &aa_defparams,
+ sizeof (struct aa_hardware_params));
+ aasink->ascii_parms.bright = 0;
+ aasink->ascii_parms.contrast = 16;
+ aasink->ascii_parms.gamma = 1.0;
+ aasink->ascii_parms.dither = 0;
+ aasink->ascii_parms.inversion = 0;
+ aasink->ascii_parms.randomval = 0;
+ aasink->aa_driver = 0;
+
+ aasink->width = -1;
+ aasink->height = -1;
+
+}
+
+static void
+gst_aasink_scale (GstAASink * aasink, guchar * src, guchar * dest,
+ gint sw, gint sh, gint dw, gint dh)
+{
+ gint ypos, yinc, y;
+ gint xpos, xinc, x;
+
+ g_return_if_fail ((dw != 0) && (dh != 0));
+
+ ypos = 0x10000;
+ yinc = (sh << 16) / dh;
+ xinc = (sw << 16) / dw;
+
+ for (y = dh; y; y--) {
+ while (ypos > 0x10000) {
+ ypos -= 0x10000;
+ src += sw;
+ }
+ xpos = 0x10000;
+ {
+ guchar *destp = dest;
+ guchar *srcp = src;
+
+ for (x = dw; x; x--) {
+ while (xpos >= 0x10000L) {
+ srcp++;
+ xpos -= 0x10000L;
+ }
+ *destp++ = *srcp;
+ xpos += xinc;
+ }
+ }
+ dest += dw;
+ ypos += yinc;
+ }
+}
+
+static void
+gst_aasink_get_times (GstBaseSink * sink, GstBuffer * buffer,
+ GstClockTime * start, GstClockTime * end)
+{
+ *start = GST_BUFFER_TIMESTAMP (buffer);
+ *end = *start + GST_BUFFER_DURATION (buffer);
+}
+
+static GstFlowReturn
+gst_aasink_render (GstBaseSink * basesink, GstBuffer * buffer)
+{
+ GstAASink *aasink;
+
+ aasink = GST_AASINK (basesink);
+
+ GST_DEBUG ("render");
+
+ gst_aasink_scale (aasink, GST_BUFFER_DATA (buffer), /* src */
+ aa_image (aasink->context), /* dest */
+ aasink->width, /* sw */
+ aasink->height, /* sh */
+ aa_imgwidth (aasink->context), /* dw */
+ aa_imgheight (aasink->context)); /* dh */
+
+ aa_render (aasink->context, &aasink->ascii_parms,
+ 0, 0, aa_imgwidth (aasink->context), aa_imgheight (aasink->context));
+ aa_flush (aasink->context);
+ aa_getevent (aasink->context, FALSE);
+
+ return GST_FLOW_OK;
+}
+
+
+static void
+gst_aasink_set_property (GObject * object, guint prop_id, const GValue * value,
+ GParamSpec * pspec)
+{
+ GstAASink *aasink;
+
+ aasink = GST_AASINK (object);
+
+ switch (prop_id) {
+ case ARG_WIDTH:
+ aasink->ascii_surf.width = g_value_get_int (value);
+ break;
+ case ARG_HEIGHT:
+ aasink->ascii_surf.height = g_value_get_int (value);
+ break;
+ case ARG_DRIVER:{
+ aasink->aa_driver = g_value_get_enum (value);
+ break;
+ }
+ case ARG_DITHER:{
+ aasink->ascii_parms.dither = g_value_get_enum (value);
+ break;
+ }
+ case ARG_BRIGHTNESS:{
+ aasink->ascii_parms.bright = g_value_get_int (value);
+ break;
+ }
+ case ARG_CONTRAST:{
+ aasink->ascii_parms.contrast = g_value_get_int (value);
+ break;
+ }
+ case ARG_GAMMA:{
+ aasink->ascii_parms.gamma = g_value_get_float (value);
+ break;
+ }
+ case ARG_INVERSION:{
+ aasink->ascii_parms.inversion = g_value_get_boolean (value);
+ break;
+ }
+ case ARG_RANDOMVAL:{
+ aasink->ascii_parms.randomval = g_value_get_int (value);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void
+gst_aasink_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstAASink *aasink;
+
+ aasink = GST_AASINK (object);
+
+ switch (prop_id) {
+ case ARG_WIDTH:{
+ g_value_set_int (value, aasink->ascii_surf.width);
+ break;
+ }
+ case ARG_HEIGHT:{
+ g_value_set_int (value, aasink->ascii_surf.height);
+ break;
+ }
+ case ARG_DRIVER:{
+ g_value_set_enum (value, aasink->aa_driver);
+ break;
+ }
+ case ARG_DITHER:{
+ g_value_set_enum (value, aasink->ascii_parms.dither);
+ break;
+ }
+ case ARG_BRIGHTNESS:{
+ g_value_set_int (value, aasink->ascii_parms.bright);
+ break;
+ }
+ case ARG_CONTRAST:{
+ g_value_set_int (value, aasink->ascii_parms.contrast);
+ break;
+ }
+ case ARG_GAMMA:{
+ g_value_set_float (value, aasink->ascii_parms.gamma);
+ break;
+ }
+ case ARG_INVERSION:{
+ g_value_set_boolean (value, aasink->ascii_parms.inversion);
+ break;
+ }
+ case ARG_RANDOMVAL:{
+ g_value_set_int (value, aasink->ascii_parms.randomval);
+ break;
+ }
+ case ARG_FRAMES_DISPLAYED:{
+ g_value_set_int (value, aasink->frames_displayed);
+ break;
+ }
+ case ARG_FRAME_TIME:{
+ g_value_set_int (value, aasink->frame_time / 1000000);
+ break;
+ }
+ default:{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ }
+}
+
+static gboolean
+gst_aasink_open (GstAASink * aasink)
+{
+ if (!aasink->context) {
+ aa_recommendhidisplay (aa_drivers[aasink->aa_driver]->shortname);
+
+ aasink->context = aa_autoinit (&aasink->ascii_surf);
+ if (aasink->context == NULL) {
+ GST_ELEMENT_ERROR (GST_ELEMENT (aasink), LIBRARY, TOO_LAZY, (NULL),
+ ("error opening aalib context"));
+ return FALSE;
+ }
+ aa_autoinitkbd (aasink->context, 0);
+ aa_resizehandler (aasink->context, (void *) aa_resize);
+ }
+ return TRUE;
+}
+
+static gboolean
+gst_aasink_close (GstAASink * aasink)
+{
+ aa_close (aasink->context);
+ aasink->context = NULL;
+
+ return TRUE;
+}
+
+static GstStateChangeReturn
+gst_aasink_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ if (!gst_aasink_open (GST_AASINK (element)))
+ goto open_failed;
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ gst_aasink_close (GST_AASINK (element));
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+
+open_failed:
+ {
+ return GST_STATE_CHANGE_FAILURE;
+ }
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "aasink", GST_RANK_NONE, GST_TYPE_AASINK))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "aasink",
+ "ASCII Art video sink",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/ext/aalib/gstaasink.h b/ext/aalib/gstaasink.h
new file mode 100644
index 0000000..03bd2ea
--- /dev/null
+++ b/ext/aalib/gstaasink.h
@@ -0,0 +1,79 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_AASINK_H__
+#define __GST_AASINK_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+
+#include <aalib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_AASINK \
+ (gst_aasink_get_type())
+#define GST_AASINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AASINK,GstAASink))
+#define GST_AASINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AASINK,GstAASinkClass))
+#define GST_IS_AASINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AASINK))
+#define GST_IS_AASINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AASINK))
+
+typedef struct _GstAASink GstAASink;
+typedef struct _GstAASinkClass GstAASinkClass;
+
+struct _GstAASink {
+ GstBaseSink parent;
+
+ gulong format;
+ gint width, height;
+
+ gint frames_displayed;
+ guint64 frame_time;
+
+ aa_context *context;
+ struct aa_hardware_params ascii_surf;
+ struct aa_renderparams ascii_parms;
+ aa_palette palette;
+ gint aa_driver;
+};
+
+struct _GstAASinkClass {
+ GstBaseSinkClass parent_class;
+
+ /* signals */
+ void (*frame_displayed) (GstElement *element);
+ void (*have_size) (GstElement *element, guint width, guint height);
+};
+
+GType gst_aasink_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_AASINKE_H__ */
diff --git a/ext/annodex/Makefile.am b/ext/annodex/Makefile.am
new file mode 100644
index 0000000..d20a01f
--- /dev/null
+++ b/ext/annodex/Makefile.am
@@ -0,0 +1,19 @@
+plugin_LTLIBRARIES = libgstannodex.la
+
+libgstannodex_la_SOURCES = \
+ gstannodex.c \
+ gstcmmlutils.c \
+ gstcmmldec.c \
+ gstcmmlenc.c \
+ gstcmmltag.c \
+ gstcmmlparser.c
+
+libgstannodex_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) $(ANNODEX_CFLAGS)
+libgstannodex_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
+ $(GST_LIBS) $(ANNODEX_LIBS) $(LIBM)
+libgstannodex_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstannodex_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstannodex.h gstcmmlutils.h gstcmmltag.h gstcmmlparser.h \
+ gstcmmldec.h gstcmmlenc.h
diff --git a/ext/annodex/Makefile.in b/ext/annodex/Makefile.in
new file mode 100644
index 0000000..5dc3209
--- /dev/null
+++ b/ext/annodex/Makefile.in
@@ -0,0 +1,863 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/annodex
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstannodex_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libgstannodex_la_OBJECTS = libgstannodex_la-gstannodex.lo \
+ libgstannodex_la-gstcmmlutils.lo \
+ libgstannodex_la-gstcmmldec.lo libgstannodex_la-gstcmmlenc.lo \
+ libgstannodex_la-gstcmmltag.lo \
+ libgstannodex_la-gstcmmlparser.lo
+libgstannodex_la_OBJECTS = $(am_libgstannodex_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstannodex_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstannodex_la_CFLAGS) $(CFLAGS) \
+ $(libgstannodex_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstannodex_la_SOURCES)
+DIST_SOURCES = $(libgstannodex_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstannodex.la
+libgstannodex_la_SOURCES = \
+ gstannodex.c \
+ gstcmmlutils.c \
+ gstcmmldec.c \
+ gstcmmlenc.c \
+ gstcmmltag.c \
+ gstcmmlparser.c
+
+libgstannodex_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) $(ANNODEX_CFLAGS)
+
+libgstannodex_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
+ $(GST_LIBS) $(ANNODEX_LIBS) $(LIBM)
+
+libgstannodex_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstannodex_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = gstannodex.h gstcmmlutils.h gstcmmltag.h gstcmmlparser.h \
+ gstcmmldec.h gstcmmlenc.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/annodex/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/annodex/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstannodex.la: $(libgstannodex_la_OBJECTS) $(libgstannodex_la_DEPENDENCIES) $(EXTRA_libgstannodex_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstannodex_la_LINK) -rpath $(plugindir) $(libgstannodex_la_OBJECTS) $(libgstannodex_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstannodex_la-gstannodex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstannodex_la-gstcmmldec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstannodex_la-gstcmmlenc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstannodex_la-gstcmmlparser.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstannodex_la-gstcmmltag.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstannodex_la-gstcmmlutils.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstannodex_la-gstannodex.lo: gstannodex.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstannodex_la_CFLAGS) $(CFLAGS) -MT libgstannodex_la-gstannodex.lo -MD -MP -MF $(DEPDIR)/libgstannodex_la-gstannodex.Tpo -c -o libgstannodex_la-gstannodex.lo `test -f 'gstannodex.c' || echo '$(srcdir)/'`gstannodex.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstannodex_la-gstannodex.Tpo $(DEPDIR)/libgstannodex_la-gstannodex.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstannodex.c' object='libgstannodex_la-gstannodex.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstannodex_la_CFLAGS) $(CFLAGS) -c -o libgstannodex_la-gstannodex.lo `test -f 'gstannodex.c' || echo '$(srcdir)/'`gstannodex.c
+
+libgstannodex_la-gstcmmlutils.lo: gstcmmlutils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstannodex_la_CFLAGS) $(CFLAGS) -MT libgstannodex_la-gstcmmlutils.lo -MD -MP -MF $(DEPDIR)/libgstannodex_la-gstcmmlutils.Tpo -c -o libgstannodex_la-gstcmmlutils.lo `test -f 'gstcmmlutils.c' || echo '$(srcdir)/'`gstcmmlutils.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstannodex_la-gstcmmlutils.Tpo $(DEPDIR)/libgstannodex_la-gstcmmlutils.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstcmmlutils.c' object='libgstannodex_la-gstcmmlutils.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstannodex_la_CFLAGS) $(CFLAGS) -c -o libgstannodex_la-gstcmmlutils.lo `test -f 'gstcmmlutils.c' || echo '$(srcdir)/'`gstcmmlutils.c
+
+libgstannodex_la-gstcmmldec.lo: gstcmmldec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstannodex_la_CFLAGS) $(CFLAGS) -MT libgstannodex_la-gstcmmldec.lo -MD -MP -MF $(DEPDIR)/libgstannodex_la-gstcmmldec.Tpo -c -o libgstannodex_la-gstcmmldec.lo `test -f 'gstcmmldec.c' || echo '$(srcdir)/'`gstcmmldec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstannodex_la-gstcmmldec.Tpo $(DEPDIR)/libgstannodex_la-gstcmmldec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstcmmldec.c' object='libgstannodex_la-gstcmmldec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstannodex_la_CFLAGS) $(CFLAGS) -c -o libgstannodex_la-gstcmmldec.lo `test -f 'gstcmmldec.c' || echo '$(srcdir)/'`gstcmmldec.c
+
+libgstannodex_la-gstcmmlenc.lo: gstcmmlenc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstannodex_la_CFLAGS) $(CFLAGS) -MT libgstannodex_la-gstcmmlenc.lo -MD -MP -MF $(DEPDIR)/libgstannodex_la-gstcmmlenc.Tpo -c -o libgstannodex_la-gstcmmlenc.lo `test -f 'gstcmmlenc.c' || echo '$(srcdir)/'`gstcmmlenc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstannodex_la-gstcmmlenc.Tpo $(DEPDIR)/libgstannodex_la-gstcmmlenc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstcmmlenc.c' object='libgstannodex_la-gstcmmlenc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstannodex_la_CFLAGS) $(CFLAGS) -c -o libgstannodex_la-gstcmmlenc.lo `test -f 'gstcmmlenc.c' || echo '$(srcdir)/'`gstcmmlenc.c
+
+libgstannodex_la-gstcmmltag.lo: gstcmmltag.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstannodex_la_CFLAGS) $(CFLAGS) -MT libgstannodex_la-gstcmmltag.lo -MD -MP -MF $(DEPDIR)/libgstannodex_la-gstcmmltag.Tpo -c -o libgstannodex_la-gstcmmltag.lo `test -f 'gstcmmltag.c' || echo '$(srcdir)/'`gstcmmltag.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstannodex_la-gstcmmltag.Tpo $(DEPDIR)/libgstannodex_la-gstcmmltag.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstcmmltag.c' object='libgstannodex_la-gstcmmltag.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstannodex_la_CFLAGS) $(CFLAGS) -c -o libgstannodex_la-gstcmmltag.lo `test -f 'gstcmmltag.c' || echo '$(srcdir)/'`gstcmmltag.c
+
+libgstannodex_la-gstcmmlparser.lo: gstcmmlparser.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstannodex_la_CFLAGS) $(CFLAGS) -MT libgstannodex_la-gstcmmlparser.lo -MD -MP -MF $(DEPDIR)/libgstannodex_la-gstcmmlparser.Tpo -c -o libgstannodex_la-gstcmmlparser.lo `test -f 'gstcmmlparser.c' || echo '$(srcdir)/'`gstcmmlparser.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstannodex_la-gstcmmlparser.Tpo $(DEPDIR)/libgstannodex_la-gstcmmlparser.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstcmmlparser.c' object='libgstannodex_la-gstcmmlparser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstannodex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstannodex_la_CFLAGS) $(CFLAGS) -c -o libgstannodex_la-gstcmmlparser.lo `test -f 'gstcmmlparser.c' || echo '$(srcdir)/'`gstcmmlparser.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/annodex/gstannodex.c b/ext/annodex/gstannodex.c
new file mode 100644
index 0000000..05e10c8
--- /dev/null
+++ b/ext/annodex/gstannodex.c
@@ -0,0 +1,167 @@
+/*
+ * gstannodex.c - GStreamer annodex plugin
+ * Copyright (C) 2005 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <gst/tag/tag.h>
+#include "gstannodex.h"
+#include "gstcmmlparser.h"
+#include "gstcmmlenc.h"
+#include "gstcmmldec.h"
+
+GstClockTime
+gst_annodex_granule_to_time (gint64 granulepos, gint64 granulerate_n,
+ gint64 granulerate_d, guint8 granuleshift)
+{
+ gint64 keyindex, keyoffset;
+ gint64 granulerate;
+ GstClockTime res;
+
+ g_return_val_if_fail (granuleshift <= 64, GST_CLOCK_TIME_NONE);
+
+ if (granulepos == -1)
+ return GST_CLOCK_TIME_NONE;
+
+ if (granulepos == 0 || granulerate_n == 0 || granulerate_d == 0)
+ return 0;
+
+ if (granuleshift != 0 && granuleshift != 64) {
+ keyindex = granulepos >> granuleshift;
+ keyoffset = granulepos - (keyindex << granuleshift);
+ granulepos = keyindex + keyoffset;
+ }
+
+ /* GST_SECOND / (granulerate_n / granulerate_d) */
+ granulerate = gst_util_uint64_scale (GST_SECOND,
+ granulerate_d, granulerate_n);
+
+ /* granulepos * granulerate */
+ res = gst_util_uint64_scale (granulepos, granulerate, 1);
+
+ return res;
+}
+
+GValueArray *
+gst_annodex_parse_headers (const gchar * headers)
+{
+ GValueArray *array;
+ GValue val = { 0 };
+ gchar *header_name = NULL;
+ gchar *header_value = NULL;
+ gchar *line, *column, *space, *tmp;
+ gchar **lines;
+ gint i = 0;
+
+ array = g_value_array_new (0);
+ g_value_init (&val, G_TYPE_STRING);
+
+ lines = g_strsplit (headers, "\r\n", 0);
+ line = lines[i];
+ while (line != NULL && *line != '\0') {
+ if (line[0] == '\t' || line[0] == ' ') {
+ /* WSP: continuation line */
+ if (header_value == NULL)
+ /* continuation line without a previous value */
+ goto fail;
+
+ tmp = g_strjoin (" ", header_value, g_strstrip (line), NULL);
+ g_free (header_value);
+ header_value = tmp;
+ } else {
+ if (header_name) {
+ g_value_take_string (&val, header_name);
+ g_value_array_append (array, &val);
+ g_value_take_string (&val, header_value);
+ g_value_array_append (array, &val);
+ }
+ /* search the column starting from line[1] as an header name can't be
+ * empty */
+ column = g_strstr_len (line + 1, strlen (line) - 1, ":");
+ if (column == NULL)
+ /* bad syntax */
+ goto fail;
+
+ if (*(space = column + 1) != ' ')
+ /* bad syntax */
+ goto fail;
+
+ header_name = g_strndup (line, column - line);
+ header_value = g_strdup (space + 1);
+ }
+
+ line = lines[++i];
+ }
+
+ if (header_name) {
+ g_value_take_string (&val, header_name);
+ g_value_array_append (array, &val);
+ g_value_take_string (&val, header_value);
+ g_value_array_append (array, &val);
+ }
+
+ g_value_unset (&val);
+ g_strfreev (lines);
+
+ return array;
+
+fail:
+ GST_WARNING ("could not parse annodex headers");
+ g_free (header_name);
+ g_free (header_value);
+ g_strfreev (lines);
+ g_value_array_free (array);
+ g_value_unset (&val);
+ return NULL;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ gst_tag_register (GST_TAG_CMML_STREAM, GST_TAG_FLAG_META,
+ GST_TYPE_CMML_TAG_STREAM, "cmml-stream", "annodex CMML stream tag", NULL);
+
+ gst_tag_register (GST_TAG_CMML_HEAD, GST_TAG_FLAG_META,
+ GST_TYPE_CMML_TAG_HEAD, "cmml-head", "annodex CMML head tag", NULL);
+
+ gst_tag_register (GST_TAG_CMML_CLIP, GST_TAG_FLAG_META,
+ GST_TYPE_CMML_TAG_CLIP, "cmml-clip", "annodex CMML clip tag", NULL);
+
+ gst_cmml_parser_init ();
+
+ if (!gst_cmml_enc_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_cmml_dec_plugin_init (plugin))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "annodex",
+ "annodex stream manipulation (info about annodex: http://www.annodex.net)",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/annodex/gstannodex.h b/ext/annodex/gstannodex.h
new file mode 100644
index 0000000..ca35e36
--- /dev/null
+++ b/ext/annodex/gstannodex.h
@@ -0,0 +1,34 @@
+/*
+ * gstannodex.h - GStreamer annodex utility functions
+ * Copyright (C) 2005 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_ANNODEX_H__
+#define __GST_ANNODEX_H__
+
+#include <gst/gst.h>
+
+GstClockTime gst_annodex_granule_to_time (gint64 granulepos,
+ gint64 granulerate_n, gint64 granulerate_d, guint8 granuleshift);
+gchar *gst_annodex_time_to_npt (GstClockTime time);
+GValueArray *gst_annodex_parse_headers (const gchar * headers);
+
+#endif /* __GST_ANNODEX_H__ */
diff --git a/ext/annodex/gstcmmldec.c b/ext/annodex/gstcmmldec.c
new file mode 100644
index 0000000..695e992
--- /dev/null
+++ b/ext/annodex/gstcmmldec.c
@@ -0,0 +1,708 @@
+/*
+ * gstcmmldec.c - GStreamer annodex CMML decoder
+ * Copyright (C) 2005 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-cmmldec
+ * @see_also: cmmlenc, oggdemux
+ *
+ * Cmmldec extracts a CMML document from a CMML bitstream.<ulink
+ * url="http://www.annodex.net/TR/draft-pfeiffer-cmml-02.html">CMML</ulink> is
+ * an XML markup language for time-continuous data maintained by the <ulink
+ * url="http:/www.annodex.org/">Annodex Foundation</ulink>.
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch -v filesrc location=annotated.ogg ! oggdemux ! cmmldec ! filesink location=annotations.cmml
+ * ]|
+ * </refsect2>
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <glib.h>
+
+#include <gst/tag/tag.h>
+#include "gstannodex.h"
+#include "gstcmmltag.h"
+#include "gstcmmldec.h"
+#include "gstcmmlutils.h"
+
+GST_DEBUG_CATEGORY_STATIC (cmmldec);
+#define GST_CAT_DEFAULT cmmldec
+
+#define CMML_IDENT_HEADER_SIZE 29
+
+enum
+{
+ ARG_0,
+ GST_CMML_DEC_WAIT_CLIP_END
+};
+
+enum
+{
+ LAST_SIGNAL
+};
+
+static GstStaticPadTemplate gst_cmml_dec_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("text/x-cmml, encoded = (boolean) false")
+ );
+
+static GstStaticPadTemplate gst_cmml_dec_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("text/x-cmml, encoded = (boolean) true")
+ );
+
+/* GstCmmlDec */
+GST_BOILERPLATE (GstCmmlDec, gst_cmml_dec, GstElement, GST_TYPE_ELEMENT);
+static void gst_cmml_dec_get_property (GObject * dec, guint property_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_cmml_dec_set_property (GObject * dec, guint property_id,
+ const GValue * value, GParamSpec * pspec);
+static const GstQueryType *gst_cmml_dec_query_types (GstPad * pad);
+static gboolean gst_cmml_dec_sink_query (GstPad * pad, GstQuery * query);
+static gboolean gst_cmml_dec_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_cmml_dec_convert (GstPad * pad, GstFormat src_fmt,
+ gint64 src_val, GstFormat * dest_fmt, gint64 * dest_val);
+static GstStateChangeReturn gst_cmml_dec_change_state (GstElement * element,
+ GstStateChange transition);
+static GstFlowReturn gst_cmml_dec_chain (GstPad * pad, GstBuffer * buffer);
+
+static GstCmmlPacketType gst_cmml_dec_parse_packet_type (GstCmmlDec * dec,
+ GstBuffer * buffer);
+static void gst_cmml_dec_parse_ident_header (GstCmmlDec * dec, GstBuffer * buf);
+static void gst_cmml_dec_parse_first_header (GstCmmlDec * dec, GstBuffer * buf);
+static void gst_cmml_dec_parse_preamble (GstCmmlDec * dec,
+ guchar * preamble, guchar * cmml_root_element);
+static void gst_cmml_dec_parse_xml (GstCmmlDec * dec,
+ guchar * data, guint size);
+static void gst_cmml_dec_parse_head (GstCmmlDec * dec, GstCmmlTagHead * head);
+static void gst_cmml_dec_parse_clip (GstCmmlDec * dec, GstCmmlTagClip * clip);
+
+static GstFlowReturn gst_cmml_dec_new_buffer (GstCmmlDec * dec,
+ guchar * data, gint size, GstBuffer ** buffer);
+static void gst_cmml_dec_push_clip (GstCmmlDec * dec, GstCmmlTagClip * clip);
+static void gst_cmml_dec_send_clip_tag (GstCmmlDec * dec,
+ GstCmmlTagClip * clip);
+
+static void gst_cmml_dec_finalize (GObject * object);
+
+static void
+gst_cmml_dec_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_cmml_dec_sink_factory);
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_cmml_dec_src_factory);
+ gst_element_class_set_details_simple (element_class, "CMML stream decoder",
+ "Codec/Decoder",
+ "Decodes CMML streams", "Alessandro Decina <alessandro@nnva.org>");
+}
+
+static void
+gst_cmml_dec_class_init (GstCmmlDecClass * dec_class)
+{
+ GObjectClass *klass = G_OBJECT_CLASS (dec_class);
+
+ GST_ELEMENT_CLASS (klass)->change_state = gst_cmml_dec_change_state;
+
+ klass->set_property = gst_cmml_dec_set_property;
+ klass->get_property = gst_cmml_dec_get_property;
+ klass->finalize = gst_cmml_dec_finalize;
+
+ g_object_class_install_property (klass, GST_CMML_DEC_WAIT_CLIP_END,
+ g_param_spec_boolean ("wait-clip-end-time",
+ "Wait clip end time",
+ "Send a tag for a clip when the clip ends, setting its end-time. "
+ "Use when you need to know both clip's start-time and end-time.",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_cmml_dec_init (GstCmmlDec * dec, GstCmmlDecClass * klass)
+{
+ dec->sinkpad =
+ gst_pad_new_from_static_template (&gst_cmml_dec_sink_factory, "sink");
+ gst_pad_set_chain_function (dec->sinkpad, gst_cmml_dec_chain);
+ gst_pad_set_query_type_function (dec->sinkpad, gst_cmml_dec_query_types);
+ gst_pad_set_query_function (dec->sinkpad, gst_cmml_dec_sink_query);
+ gst_pad_set_event_function (dec->sinkpad, gst_cmml_dec_sink_event);
+ gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
+
+ dec->srcpad =
+ gst_pad_new_from_static_template (&gst_cmml_dec_src_factory, "src");
+ gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
+
+ dec->wait_clip_end = FALSE;
+}
+
+static void
+gst_cmml_dec_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstCmmlDec *dec = GST_CMML_DEC (object);
+
+ switch (property_id) {
+ case GST_CMML_DEC_WAIT_CLIP_END:
+ g_value_set_boolean (value, dec->wait_clip_end);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+gst_cmml_dec_set_property (GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstCmmlDec *dec = GST_CMML_DEC (object);
+
+ switch (property_id) {
+ case GST_CMML_DEC_WAIT_CLIP_END:
+ dec->wait_clip_end = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (dec, property_id, pspec);
+ }
+}
+
+static void
+gst_cmml_dec_finalize (GObject * object)
+{
+ GstCmmlDec *dec = GST_CMML_DEC (object);
+
+ if (dec->tracks) {
+ gst_cmml_track_list_destroy (dec->tracks);
+ dec->tracks = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstStateChangeReturn
+gst_cmml_dec_change_state (GstElement * element, GstStateChange transition)
+{
+ GstCmmlDec *dec = GST_CMML_DEC (element);
+ GstStateChangeReturn res;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ dec->parser = gst_cmml_parser_new (GST_CMML_PARSER_DECODE);
+ dec->parser->user_data = dec;
+ dec->parser->preamble_callback =
+ (GstCmmlParserPreambleCallback) gst_cmml_dec_parse_preamble;
+ dec->parser->head_callback =
+ (GstCmmlParserHeadCallback) gst_cmml_dec_parse_head;
+ dec->parser->clip_callback =
+ (GstCmmlParserClipCallback) gst_cmml_dec_parse_clip;
+ dec->major = -1;
+ dec->minor = -1;
+ dec->granulerate_n = -1;
+ dec->granulerate_d = -1;
+ dec->granuleshift = 0;
+ dec->granulepos = 0;
+ dec->flow_return = GST_FLOW_OK;
+ dec->sent_root = FALSE;
+ dec->tracks = gst_cmml_track_list_new ();
+ break;
+ default:
+ break;
+ }
+
+ res = parent_class->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_cmml_parser_free (dec->parser);
+ gst_cmml_track_list_destroy (dec->tracks);
+ dec->tracks = NULL;
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+static const GstQueryType *
+gst_cmml_dec_query_types (GstPad * pad)
+{
+ static const GstQueryType query_types[] = {
+ GST_QUERY_CONVERT,
+ 0
+ };
+
+ return query_types;
+}
+
+static gboolean
+gst_cmml_dec_sink_query (GstPad * pad, GstQuery * query)
+{
+ gboolean res = FALSE;
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_CONVERT:
+ {
+ GstFormat src_fmt, dest_fmt;
+ gint64 src_val, dest_val;
+
+ gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+ res = gst_cmml_dec_convert (pad, src_fmt, src_val, &dest_fmt, &dest_val);
+ if (res)
+ gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return res;
+}
+
+static gboolean
+gst_cmml_dec_convert (GstPad * pad,
+ GstFormat src_fmt, gint64 src_val, GstFormat * dest_fmt, gint64 * dest_val)
+{
+ GstCmmlDec *dec = GST_CMML_DEC (GST_PAD_PARENT (pad));
+ gboolean res = FALSE;
+
+ switch (src_fmt) {
+ case GST_FORMAT_DEFAULT:
+ switch (*dest_fmt) {
+ case GST_FORMAT_TIME:
+ {
+ *dest_val = gst_annodex_granule_to_time (src_val, dec->granulerate_n,
+ dec->granulerate_d, dec->granuleshift);
+ res = TRUE;
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+static gboolean
+gst_cmml_dec_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstCmmlDec *dec = GST_CMML_DEC (GST_PAD_PARENT (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ {
+ GstBuffer *buffer;
+ GstCmmlTagClip *clip;
+ GList *clips, *walk;
+
+ GST_INFO_OBJECT (dec, "got EOS, flushing clips");
+
+ /* since we output a clip when the next one in the same track is found, on
+ * EOS we need to output the last clip (if any) of every track
+ */
+ clips = gst_cmml_track_list_get_clips (dec->tracks);
+ for (walk = clips; walk; walk = g_list_next (walk)) {
+ clip = GST_CMML_TAG_CLIP (walk->data);
+ gst_cmml_dec_push_clip (dec, clip);
+ if (dec->wait_clip_end) {
+ clip->end_time = dec->timestamp;
+ gst_cmml_dec_send_clip_tag (dec, clip);
+ }
+ }
+ g_list_free (clips);
+
+ /* send the cmml end tag */
+ dec->flow_return = gst_cmml_dec_new_buffer (dec,
+ (guchar *) "</cmml>", strlen ("</cmml>"), &buffer);
+
+ if (dec->flow_return == GST_FLOW_OK)
+ dec->flow_return = gst_pad_push (dec->srcpad, buffer);
+ if (dec->flow_return == GST_FLOW_NOT_LINKED)
+ dec->flow_return = GST_FLOW_OK; /* Ignore NOT_LINKED */
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return gst_pad_event_default (pad, event);
+}
+
+static GstFlowReturn
+gst_cmml_dec_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstCmmlDec *dec = GST_CMML_DEC (GST_PAD_PARENT (pad));
+ GstCmmlPacketType packet;
+
+ if (GST_BUFFER_SIZE (buffer) == 0) {
+ /* the EOS page could be empty */
+ dec->flow_return = GST_FLOW_OK;
+ goto done;
+ }
+
+ dec->granulepos = GST_BUFFER_OFFSET_END (buffer);
+ dec->timestamp = gst_annodex_granule_to_time (dec->granulepos,
+ dec->granulerate_n, dec->granulerate_d, dec->granuleshift);
+
+ /* identify the packet type */
+ packet = gst_cmml_dec_parse_packet_type (dec, buffer);
+
+ /* handle the packet. the handler will set dec->flow_return */
+ switch (packet) {
+ case GST_CMML_PACKET_IDENT_HEADER:
+ if (dec->sent_root == FALSE)
+ /* don't parse the ident again in case of seeking to the beginning */
+ gst_cmml_dec_parse_ident_header (dec, buffer);
+ break;
+ case GST_CMML_PACKET_FIRST_HEADER:
+ if (dec->sent_root == FALSE)
+ /* don't parse the xml preamble if it has already been parsed because it
+ * would error out, so seeking to the beginning would fail */
+ gst_cmml_dec_parse_first_header (dec, buffer);
+ break;
+ case GST_CMML_PACKET_SECOND_HEADER:
+ case GST_CMML_PACKET_CLIP:
+ gst_cmml_dec_parse_xml (dec,
+ GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
+ break;
+ case GST_CMML_PACKET_UNKNOWN:
+ default:
+ GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("unknown packet type"));
+ dec->flow_return = GST_FLOW_ERROR;
+ }
+
+done:
+ gst_buffer_unref (buffer);
+ return dec->flow_return;
+}
+
+/* finds the packet type of the buffer
+ */
+static GstCmmlPacketType
+gst_cmml_dec_parse_packet_type (GstCmmlDec * dec, GstBuffer * buffer)
+{
+ GstCmmlPacketType packet_type = GST_CMML_PACKET_UNKNOWN;
+ gchar *data = (gchar *) GST_BUFFER_DATA (buffer);
+ guint size = GST_BUFFER_SIZE (buffer);
+
+ if (size >= 8 && !memcmp (data, "CMML\0\0\0\0", 8)) {
+ packet_type = GST_CMML_PACKET_IDENT_HEADER;
+ } else if (size >= 5) {
+ if (!strncmp (data, "<?xml", 5))
+ packet_type = GST_CMML_PACKET_FIRST_HEADER;
+ else if (!strncmp (data, "<head", 5))
+ packet_type = GST_CMML_PACKET_SECOND_HEADER;
+ else if (!strncmp (data, "<clip", 5))
+ packet_type = GST_CMML_PACKET_CLIP;
+ }
+
+ return packet_type;
+}
+
+/* creates a new buffer and sets caps and timestamp on it
+ */
+static GstFlowReturn
+gst_cmml_dec_new_buffer (GstCmmlDec * dec,
+ guchar * data, gint size, GstBuffer ** buffer)
+{
+ GstFlowReturn res;
+
+ res = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE,
+ size, gst_static_pad_template_get_caps (&gst_cmml_dec_src_factory),
+ buffer);
+
+ if (res == GST_FLOW_OK) {
+ if (data)
+ memcpy (GST_BUFFER_DATA (*buffer), data, size);
+ GST_BUFFER_TIMESTAMP (*buffer) = dec->timestamp;
+ } else if (res == GST_FLOW_NOT_LINKED) {
+ GST_DEBUG_OBJECT (dec, "alloc function return NOT-LINKED, ignoring");
+ } else {
+ GST_WARNING_OBJECT (dec, "alloc function returned error %s",
+ gst_flow_get_name (res));
+ }
+
+ return res;
+}
+
+/* parses the first CMML packet (the ident header)
+ */
+static void
+gst_cmml_dec_parse_ident_header (GstCmmlDec * dec, GstBuffer * buffer)
+{
+ guint8 *data = GST_BUFFER_DATA (buffer);
+
+ /* the ident header has a fixed length */
+ if (GST_BUFFER_SIZE (buffer) != CMML_IDENT_HEADER_SIZE) {
+ GST_ELEMENT_ERROR (dec, STREAM, DECODE,
+ (NULL), ("wrong ident header size: %d", GST_BUFFER_SIZE (buffer)));
+ dec->flow_return = GST_FLOW_ERROR;
+
+ return;
+ }
+
+ data += 8;
+ dec->major = GST_READ_UINT16_LE (data);
+ data += 2;
+ dec->minor = GST_READ_UINT16_LE (data);
+ data += 2;
+ dec->granulerate_n = GST_READ_UINT64_LE (data);
+ data += 8;
+ dec->granulerate_d = GST_READ_UINT64_LE (data);
+ data += 8;
+ dec->granuleshift = GST_READ_UINT8 (data);
+
+ GST_INFO_OBJECT (dec, "bitstream initialized "
+ "(major: %" G_GINT16_FORMAT " minor: %" G_GINT16_FORMAT
+ " granulerate_n: %" G_GINT64_FORMAT " granulerate_d: %" G_GINT64_FORMAT
+ " granuleshift: %d)",
+ dec->major, dec->minor,
+ dec->granulerate_n, dec->granulerate_d, dec->granuleshift);
+
+ dec->flow_return = GST_FLOW_OK;
+}
+
+/* parses the first secondary header.
+ * the first secondary header contains the xml version, the doctype and the
+ * optional "cmml" processing instruction.
+ */
+static void
+gst_cmml_dec_parse_first_header (GstCmmlDec * dec, GstBuffer * buffer)
+{
+ gst_cmml_dec_parse_xml (dec,
+ GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
+
+ /* if there is a processing instruction, gst_cmml_dec_parse_preamble
+ * will be triggered. Otherwise we need to call it manually.
+ */
+ if (dec->flow_return == GST_FLOW_OK && !dec->sent_root) {
+ guchar *preamble = (guchar *) g_strndup ((gchar *) GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer));
+
+ gst_cmml_dec_parse_preamble (dec, preamble, (guchar *) "<cmml>");
+ g_free (preamble);
+ }
+}
+
+/* feeds data into the cmml parser.
+ */
+static void
+gst_cmml_dec_parse_xml (GstCmmlDec * dec, guchar * data, guint size)
+{
+ GError *err = NULL;
+
+ if (!gst_cmml_parser_parse_chunk (dec->parser, (gchar *) data, size, &err)) {
+ GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("%s", err->message));
+ g_error_free (err);
+ dec->flow_return = GST_FLOW_ERROR;
+ }
+}
+
+static void
+gst_cmml_dec_parse_preamble (GstCmmlDec * dec, guchar * preamble,
+ guchar * root_element)
+{
+ GstBuffer *buffer;
+ guchar *encoded_preamble;
+
+ encoded_preamble = (guchar *) g_strconcat ((gchar *) preamble,
+ (gchar *) root_element, NULL);
+
+ /* send the root element to the internal parser */
+ gst_cmml_dec_parse_xml (dec, root_element, strlen ((gchar *) root_element));
+ dec->sent_root = TRUE;
+
+ /* push the root element */
+ dec->flow_return = gst_cmml_dec_new_buffer (dec,
+ encoded_preamble, strlen ((gchar *) encoded_preamble), &buffer);
+ if (dec->flow_return == GST_FLOW_OK) {
+ dec->flow_return = gst_pad_push (dec->srcpad, buffer);
+ }
+
+ if (dec->flow_return == GST_FLOW_OK) {
+ GST_INFO_OBJECT (dec, "preamble parsed");
+ }
+
+ g_free (encoded_preamble);
+ return;
+}
+
+/* outputs the cmml head element and send TITLE and CMML_HEAD tags.
+ * This callback is registered with dec->parser. It is called when the
+ * head element is parsed.
+ */
+static void
+gst_cmml_dec_parse_head (GstCmmlDec * dec, GstCmmlTagHead * head)
+{
+ GstTagList *tags;
+ GValue str_val = { 0 }, title_val = {
+ 0};
+ guchar *head_str;
+ GstBuffer *buffer;
+
+ GST_DEBUG_OBJECT (dec, "found CMML head (title: %s base: %s)",
+ head->title, head->base);
+
+ /* create the GST_TAG_TITLE tag */
+ g_value_init (&str_val, G_TYPE_STRING);
+ g_value_init (&title_val, gst_tag_get_type (GST_TAG_TITLE));
+ g_value_set_string (&str_val, (gchar *) head->title);
+ g_value_transform (&str_val, &title_val);
+
+ tags = gst_tag_list_new ();
+ gst_tag_list_add_values (tags, GST_TAG_MERGE_APPEND,
+ GST_TAG_TITLE, &title_val, NULL);
+ gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_CMML_HEAD, head, NULL);
+ gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, tags);
+
+ g_value_unset (&str_val);
+ g_value_unset (&title_val);
+
+ head_str = gst_cmml_parser_tag_head_to_string (dec->parser, head);
+
+ dec->flow_return = gst_cmml_dec_new_buffer (dec,
+ head_str, strlen ((gchar *) head_str), &buffer);
+ g_free (head_str);
+ if (dec->flow_return == GST_FLOW_OK)
+ dec->flow_return = gst_pad_push (dec->srcpad, buffer);
+ if (dec->flow_return == GST_FLOW_NOT_LINKED)
+ dec->flow_return = GST_FLOW_OK; /* Ignore NOT_LINKED */
+}
+
+/* send a TAG_MESSAGE event for a clip */
+static void
+gst_cmml_dec_send_clip_tag (GstCmmlDec * dec, GstCmmlTagClip * clip)
+{
+ GstTagList *tags;
+
+ GST_DEBUG_OBJECT (dec, "sending clip tag %s", clip->id);
+
+ tags = gst_tag_list_new ();
+ gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_CMML_CLIP, clip, NULL);
+ gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, tags);
+}
+
+/* push the string representation of a clip */
+static void
+gst_cmml_dec_push_clip (GstCmmlDec * dec, GstCmmlTagClip * clip)
+{
+ GstBuffer *buffer;
+ guchar *clip_str;
+
+ GST_DEBUG_OBJECT (dec, "pushing clip %s", clip->id);
+
+ clip_str = gst_cmml_parser_tag_clip_to_string (dec->parser, clip);
+ dec->flow_return = gst_cmml_dec_new_buffer (dec,
+ clip_str, strlen ((gchar *) clip_str), &buffer);
+ if (dec->flow_return == GST_FLOW_OK)
+ dec->flow_return = gst_pad_push (dec->srcpad, buffer);
+ if (dec->flow_return == GST_FLOW_NOT_LINKED)
+ dec->flow_return = GST_FLOW_OK; /* Ignore NOT_LINKED */
+
+ g_free (clip_str);
+}
+
+/* decode a clip tag
+ * this callback is registered with dec->parser. It is called whenever a
+ * clip is parsed.
+ */
+static void
+gst_cmml_dec_parse_clip (GstCmmlDec * dec, GstCmmlTagClip * clip)
+{
+ GstCmmlTagClip *prev_clip;
+
+ dec->flow_return = GST_FLOW_OK;
+
+ if (clip->empty)
+ GST_INFO_OBJECT (dec, "parsing empty clip");
+ else
+ GST_INFO_OBJECT (dec, "parsing clip (id: %s)", clip->id);
+
+ clip->start_time = dec->timestamp;
+ if (clip->start_time == GST_CLOCK_TIME_NONE) {
+ GST_ELEMENT_ERROR (dec, STREAM, DECODE,
+ (NULL), ("invalid clip start time"));
+
+ dec->flow_return = GST_FLOW_ERROR;
+ return;
+ }
+
+ /* get the last clip in the current track */
+ prev_clip = gst_cmml_track_list_get_track_last_clip (dec->tracks,
+ (gchar *) clip->track);
+ if (prev_clip) {
+ /* output the previous clip */
+ if (clip->empty)
+ /* the current clip marks the end of the previous one */
+ prev_clip->end_time = clip->start_time;
+
+ gst_cmml_dec_push_clip (dec, prev_clip);
+ }
+
+ if (dec->wait_clip_end) {
+ /* now it's time to send the tag for the previous clip */
+ if (prev_clip) {
+ prev_clip->end_time = clip->start_time;
+ gst_cmml_dec_send_clip_tag (dec, prev_clip);
+ }
+ } else if (!clip->empty) {
+ /* send the tag for the current clip */
+ gst_cmml_dec_send_clip_tag (dec, clip);
+ }
+
+ if (prev_clip)
+ gst_cmml_track_list_del_clip (dec->tracks, prev_clip);
+
+ if (!clip->empty)
+ if (!gst_cmml_track_list_has_clip (dec->tracks, clip))
+ gst_cmml_track_list_add_clip (dec->tracks, clip);
+}
+
+gboolean
+gst_cmml_dec_plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "cmmldec", GST_RANK_PRIMARY,
+ GST_TYPE_CMML_DEC))
+ return FALSE;
+
+ GST_DEBUG_CATEGORY_INIT (cmmldec, "cmmldec", 0,
+ "annodex CMML decoding element");
+
+ return TRUE;
+}
diff --git a/ext/annodex/gstcmmldec.h b/ext/annodex/gstcmmldec.h
new file mode 100644
index 0000000..27a6c55
--- /dev/null
+++ b/ext/annodex/gstcmmldec.h
@@ -0,0 +1,98 @@
+/*
+ * gstcmmldec.h - GStreamer annodex CMML decoder
+ * Copyright (C) 2005 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CMML_DEC_H__
+#define __GST_CMML_DEC_H__
+
+#include <gst/gst.h>
+#include <gst/gstformat.h>
+#include <gst/controller/gstcontroller.h>
+
+#include "gstcmmlparser.h"
+
+/* GstCmmlDec */
+#define GST_TYPE_CMML_DEC (gst_cmml_dec_get_type())
+#define GST_CMML_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CMML_DEC, GstCmmlDec))
+#define GST_CMML_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CMML_DEC, GstCmmlDecClass))
+#define GST_IS_CMML_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_CMML_DEC))
+#define GST_IS_CMML_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_CMML_DEC))
+#define GST_CMML_DEC_GET_CLASS(klass) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_CMML_DEC, GstCmmlDecClass))
+
+typedef struct _GstCmmlDec GstCmmlDec;
+typedef struct _GstCmmlDecClass GstCmmlDecClass;
+typedef enum _GstCmmlPacketType GstCmmlPacketType;
+
+enum _GstCmmlPacketType
+{
+ GST_CMML_PACKET_UNKNOWN,
+ GST_CMML_PACKET_IDENT_HEADER,
+ GST_CMML_PACKET_FIRST_HEADER,
+ GST_CMML_PACKET_SECOND_HEADER,
+ GST_CMML_PACKET_CLIP
+};
+
+struct _GstCmmlDec
+{
+ GstElement element;
+
+ /* element part */
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ /* bitstream part */
+ gint16 major; /* bitstream version major */
+ gint16 minor; /* bitstream version minor */
+ gint64 granulerate_n; /* bitrstream granulerate numerator */
+ gint64 granulerate_d; /* bitstream granulerate denominator */
+ gint8 granuleshift; /* bitstreamgranuleshift */
+ gint64 granulepos; /* bitstream granule position */
+ GstClockTime timestamp; /* timestamp of the last buffer */
+
+ /* decoder part */
+ GstCmmlParser *parser; /* cmml parser */
+ gboolean sent_root;
+ GstFlowReturn flow_return; /* _chain return value */
+ gboolean wait_clip_end; /* when TRUE, the GST_TAG_MESSAGE for a
+ * clip is sent when the next clip (or EOS)
+ * is found, so that the clip end-time is
+ * known. This is useful for pre-extracting
+ * the clips.
+ */
+ GHashTable *tracks;
+};
+
+struct _GstCmmlDecClass
+{
+ GstElementClass parent_class;
+};
+
+GType gst_cmml_dec_get_type (void);
+
+gboolean gst_cmml_dec_plugin_init (GstPlugin * plugin);
+
+#endif /* __GST_CMML_DEC_H__ */
diff --git a/ext/annodex/gstcmmlenc.c b/ext/annodex/gstcmmlenc.c
new file mode 100644
index 0000000..7bdfc1e
--- /dev/null
+++ b/ext/annodex/gstcmmlenc.c
@@ -0,0 +1,631 @@
+/*
+ * gstcmmlenc.c - GStreamer CMML encoder
+ * Copyright (C) 2005 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-cmmlenc
+ * @see_also: cmmldec, oggmux
+ *
+ * Cmmlenc encodes a CMML document into a CMML stream. <ulink
+ * url="http://www.annodex.net/TR/draft-pfeiffer-cmml-02.html">CMML</ulink> is
+ * an XML markup language for time-continuous data maintained by the <ulink
+ * url="http:/www.annodex.org/">Annodex Foundation</ulink>.
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch -v filesrc location=annotations.cmml ! cmmlenc ! oggmux name=mux ! filesink location=annotated.ogg
+ * ]|
+ * </refsect2>
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include "gstcmmlenc.h"
+#include "gstannodex.h"
+
+GST_DEBUG_CATEGORY_STATIC (cmmlenc);
+#define GST_CAT_DEFAULT cmmlenc
+
+#define CMML_IDENT_HEADER_SIZE 29
+
+enum
+{
+ ARG_0,
+ GST_CMML_ENC_GRANULERATE_N,
+ GST_CMML_ENC_GRANULERATE_D,
+ GST_CMML_ENC_GRANULESHIFT
+};
+
+enum
+{
+ LAST_SIGNAL
+};
+
+static GstStaticPadTemplate gst_cmml_enc_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("text/x-cmml, encoded = (boolean) true")
+ );
+
+static GstStaticPadTemplate gst_cmml_enc_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("text/x-cmml, encoded = (boolean) false")
+ );
+
+GST_BOILERPLATE (GstCmmlEnc, gst_cmml_enc, GstElement, GST_TYPE_ELEMENT);
+static void gst_cmml_enc_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_cmml_enc_set_property (GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec);
+static gboolean gst_cmml_enc_sink_event (GstPad * pad, GstEvent * event);
+static GstStateChangeReturn gst_cmml_enc_change_state (GstElement * element,
+ GstStateChange transition);
+static GstFlowReturn gst_cmml_enc_chain (GstPad * pad, GstBuffer * buffer);
+static void gst_cmml_enc_parse_preamble (GstCmmlEnc * enc,
+ guchar * preamble, guchar * processing_instruction);
+static void gst_cmml_enc_parse_end_tag (GstCmmlEnc * enc);
+static void gst_cmml_enc_parse_tag_head (GstCmmlEnc * enc,
+ GstCmmlTagHead * head);
+static void gst_cmml_enc_parse_tag_clip (GstCmmlEnc * enc,
+ GstCmmlTagClip * tag);
+static GstFlowReturn gst_cmml_enc_new_buffer (GstCmmlEnc * enc,
+ guchar * data, gint size, GstBuffer ** buffer);
+static GstFlowReturn gst_cmml_enc_push_clip (GstCmmlEnc * enc,
+ GstCmmlTagClip * clip, GstClockTime prev_clip_time);
+static GstFlowReturn gst_cmml_enc_push (GstCmmlEnc * enc, GstBuffer * buffer);
+
+static void gst_cmml_enc_finalize (GObject * object);
+
+static void
+gst_cmml_enc_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_cmml_enc_sink_factory);
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_cmml_enc_src_factory);
+ gst_element_class_set_details_simple (element_class, "CMML streams encoder",
+ "Codec/Encoder",
+ "Encodes CMML streams", "Alessandro Decina <alessandro@nnva.org>");
+}
+
+static void
+gst_cmml_enc_class_init (GstCmmlEncClass * enc_class)
+{
+ GObjectClass *klass = G_OBJECT_CLASS (enc_class);
+
+ klass->get_property = gst_cmml_enc_get_property;
+ klass->set_property = gst_cmml_enc_set_property;
+ klass->finalize = gst_cmml_enc_finalize;
+
+ g_object_class_install_property (klass, GST_CMML_ENC_GRANULERATE_N,
+ g_param_spec_int64 ("granule-rate-numerator",
+ "Granulerate numerator",
+ "Granulerate numerator",
+ 0, G_MAXINT64, 1000,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_ENC_GRANULERATE_D,
+ g_param_spec_int64 ("granule-rate-denominator",
+ "Granulerate denominator",
+ "Granulerate denominator",
+ 0, G_MAXINT64, 1,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_ENC_GRANULESHIFT,
+ g_param_spec_uchar ("granule-shift",
+ "Granuleshift",
+ "The number of lower bits to use for partitioning a granule position",
+ 0, 64, 32,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ GST_ELEMENT_CLASS (klass)->change_state = gst_cmml_enc_change_state;
+}
+
+static void
+gst_cmml_enc_init (GstCmmlEnc * enc, GstCmmlEncClass * klass)
+{
+ enc->sinkpad =
+ gst_pad_new_from_static_template (&gst_cmml_enc_sink_factory, "sink");
+ gst_pad_set_chain_function (enc->sinkpad, gst_cmml_enc_chain);
+ gst_pad_set_event_function (enc->sinkpad, gst_cmml_enc_sink_event);
+ gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
+
+ enc->srcpad =
+ gst_pad_new_from_static_template (&gst_cmml_enc_src_factory, "src");
+ gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
+
+ enc->major = 3;
+ enc->minor = 0;
+}
+
+static void
+gst_cmml_enc_set_property (GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstCmmlEnc *enc = GST_CMML_ENC (object);
+
+ switch (property_id) {
+ case GST_CMML_ENC_GRANULERATE_N:
+ /* XXX: may need to flush clips */
+ enc->granulerate_n = g_value_get_int64 (value);
+ break;
+ case GST_CMML_ENC_GRANULERATE_D:
+ enc->granulerate_d = g_value_get_int64 (value);
+ break;
+ case GST_CMML_ENC_GRANULESHIFT:
+ enc->granuleshift = g_value_get_uchar (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+gst_cmml_enc_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstCmmlEnc *enc = GST_CMML_ENC (object);
+
+ switch (property_id) {
+ case GST_CMML_ENC_GRANULERATE_N:
+ g_value_set_int64 (value, enc->granulerate_n);
+ break;
+ case GST_CMML_ENC_GRANULERATE_D:
+ g_value_set_int64 (value, enc->granulerate_d);
+ break;
+ case GST_CMML_ENC_GRANULESHIFT:
+ g_value_set_uchar (value, enc->granuleshift);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+gst_cmml_enc_finalize (GObject * object)
+{
+ GstCmmlEnc *enc = GST_CMML_ENC (object);
+
+ if (enc->tracks) {
+ gst_cmml_track_list_destroy (enc->tracks);
+ enc->tracks = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstStateChangeReturn
+gst_cmml_enc_change_state (GstElement * element, GstStateChange transition)
+{
+ GstCmmlEnc *enc = GST_CMML_ENC (element);
+ GstStateChangeReturn res;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ enc->parser = gst_cmml_parser_new (GST_CMML_PARSER_ENCODE);
+ enc->parser->user_data = enc;
+ enc->parser->preamble_callback =
+ (GstCmmlParserPreambleCallback) gst_cmml_enc_parse_preamble;
+ enc->parser->head_callback =
+ (GstCmmlParserHeadCallback) gst_cmml_enc_parse_tag_head;
+ enc->parser->clip_callback =
+ (GstCmmlParserClipCallback) gst_cmml_enc_parse_tag_clip;
+ enc->parser->cmml_end_callback =
+ (GstCmmlParserCmmlEndCallback) gst_cmml_enc_parse_end_tag;
+ enc->tracks = gst_cmml_track_list_new ();
+ enc->sent_headers = FALSE;
+ enc->sent_eos = FALSE;
+ enc->flow_return = GST_FLOW_OK;
+ break;
+ default:
+ break;
+ }
+
+ res = parent_class->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ {
+ gst_cmml_track_list_destroy (enc->tracks);
+ enc->tracks = NULL;
+ g_free (enc->preamble);
+ enc->preamble = NULL;
+ gst_cmml_parser_free (enc->parser);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return res;
+}
+
+static gboolean
+gst_cmml_enc_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstCmmlEnc *enc = GST_CMML_ENC (GST_PAD_PARENT (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ {
+ if (!enc->sent_eos)
+ gst_cmml_enc_parse_end_tag (enc);
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return gst_pad_event_default (pad, event);
+}
+
+static GstFlowReturn
+gst_cmml_enc_new_buffer (GstCmmlEnc * enc,
+ guchar * data, gint size, GstBuffer ** buffer)
+{
+ GstFlowReturn res;
+
+ res = gst_pad_alloc_buffer (enc->srcpad, GST_BUFFER_OFFSET_NONE, size,
+ NULL, buffer);
+ if (res == GST_FLOW_OK) {
+ if (data)
+ memcpy (GST_BUFFER_DATA (*buffer), data, size);
+ } else {
+ GST_WARNING_OBJECT (enc, "alloc function returned error %s",
+ gst_flow_get_name (res));
+ }
+
+ return res;
+}
+
+static GstCaps *
+gst_cmml_enc_set_header_on_caps (GstCmmlEnc * enc, GstCaps * caps,
+ GstBuffer * ident, GstBuffer * preamble, GstBuffer * head)
+{
+ GValue array = { 0 };
+ GValue value = { 0 };
+ GstStructure *structure;
+ GstBuffer *buffer;
+
+ caps = gst_caps_make_writable (caps);
+ structure = gst_caps_get_structure (caps, 0);
+
+ g_value_init (&array, GST_TYPE_ARRAY);
+ g_value_init (&value, GST_TYPE_BUFFER);
+
+ /* Make copies of header buffers to avoid circular references */
+ buffer = gst_buffer_copy (ident);
+ gst_value_set_buffer (&value, buffer);
+ gst_value_array_append_value (&array, &value);
+ gst_buffer_unref (buffer);
+
+ buffer = gst_buffer_copy (preamble);
+ gst_value_set_buffer (&value, buffer);
+ gst_value_array_append_value (&array, &value);
+ gst_buffer_unref (buffer);
+
+ buffer = gst_buffer_copy (head);
+ gst_value_set_buffer (&value, buffer);
+ gst_value_array_append_value (&array, &value);
+ gst_buffer_unref (buffer);
+
+ GST_BUFFER_FLAG_SET (ident, GST_BUFFER_FLAG_IN_CAPS);
+ GST_BUFFER_FLAG_SET (preamble, GST_BUFFER_FLAG_IN_CAPS);
+ GST_BUFFER_FLAG_SET (head, GST_BUFFER_FLAG_IN_CAPS);
+
+ gst_structure_set_value (structure, "streamheader", &array);
+
+ g_value_unset (&value);
+ g_value_unset (&array);
+
+ return caps;
+}
+
+/* create a CMML ident header buffer
+ */
+static GstFlowReturn
+gst_cmml_enc_new_ident_header (GstCmmlEnc * enc, GstBuffer ** buffer)
+{
+ guint8 ident_header[CMML_IDENT_HEADER_SIZE];
+ guint8 *wptr = ident_header;
+
+ memcpy (wptr, "CMML\0\0\0\0", 8);
+ wptr += 8;
+ GST_WRITE_UINT16_LE (wptr, enc->major);
+ wptr += 2;
+ GST_WRITE_UINT16_LE (wptr, enc->minor);
+ wptr += 2;
+ GST_WRITE_UINT64_LE (wptr, enc->granulerate_n);
+ wptr += 8;
+ GST_WRITE_UINT64_LE (wptr, enc->granulerate_d);
+ wptr += 8;
+ *wptr = enc->granuleshift;
+
+ return gst_cmml_enc_new_buffer (enc,
+ (guchar *) & ident_header, CMML_IDENT_HEADER_SIZE, buffer);
+}
+
+/* parse the CMML preamble */
+static void
+gst_cmml_enc_parse_preamble (GstCmmlEnc * enc,
+ guchar * preamble, guchar * processing_instruction)
+{
+ GST_INFO_OBJECT (enc, "parsing preamble");
+
+ /* save the preamble: it will be pushed when the head tag is found */
+ enc->preamble = (guchar *) g_strconcat ((gchar *) preamble,
+ (gchar *) processing_instruction, NULL);
+}
+
+/* parse the CMML end tag */
+static void
+gst_cmml_enc_parse_end_tag (GstCmmlEnc * enc)
+{
+ GstBuffer *buffer;
+
+ GST_INFO_OBJECT (enc, "parsing end tag");
+
+ /* push an empty buffer to signal EOS */
+ enc->flow_return = gst_cmml_enc_new_buffer (enc, NULL, 0, &buffer);
+ if (enc->flow_return == GST_FLOW_OK) {
+ /* set granulepos 0 on EOS */
+ GST_BUFFER_OFFSET_END (buffer) = 0;
+ enc->flow_return = gst_cmml_enc_push (enc, buffer);
+ enc->sent_eos = TRUE;
+ }
+
+ return;
+}
+
+/* encode the CMML head tag and push the CMML headers
+ */
+static void
+gst_cmml_enc_parse_tag_head (GstCmmlEnc * enc, GstCmmlTagHead * head)
+{
+ GList *headers = NULL;
+ GList *walk;
+ guchar *head_string;
+ GstCaps *caps;
+ GstBuffer *ident_buf, *preamble_buf, *head_buf;
+ GstBuffer *buffer;
+
+ if (enc->preamble == NULL)
+ goto flow_unexpected;
+
+ GST_INFO_OBJECT (enc, "parsing head tag");
+
+ enc->flow_return = gst_cmml_enc_new_ident_header (enc, &ident_buf);
+ if (enc->flow_return != GST_FLOW_OK)
+ goto alloc_error;
+ headers = g_list_append (headers, ident_buf);
+
+ enc->flow_return = gst_cmml_enc_new_buffer (enc,
+ enc->preamble, strlen ((gchar *) enc->preamble), &preamble_buf);
+ if (enc->flow_return != GST_FLOW_OK)
+ goto alloc_error;
+ headers = g_list_append (headers, preamble_buf);
+
+ head_string = gst_cmml_parser_tag_head_to_string (enc->parser, head);
+ enc->flow_return = gst_cmml_enc_new_buffer (enc,
+ head_string, strlen ((gchar *) head_string), &head_buf);
+ g_free (head_string);
+ if (enc->flow_return != GST_FLOW_OK)
+ goto alloc_error;
+ headers = g_list_append (headers, head_buf);
+
+ caps = gst_pad_get_caps (enc->srcpad);
+ caps = gst_cmml_enc_set_header_on_caps (enc, caps,
+ ident_buf, preamble_buf, head_buf);
+
+ while (headers) {
+ buffer = GST_BUFFER (headers->data);
+ /* set granulepos 0 on headers */
+ GST_BUFFER_OFFSET_END (buffer) = 0;
+ gst_buffer_set_caps (buffer, caps);
+
+ enc->flow_return = gst_cmml_enc_push (enc, buffer);
+ headers = g_list_delete_link (headers, headers);
+
+ if (enc->flow_return != GST_FLOW_OK)
+ goto push_error;
+ }
+
+ gst_caps_unref (caps);
+
+ enc->sent_headers = TRUE;
+ return;
+
+flow_unexpected:
+ GST_ELEMENT_ERROR (enc, STREAM, ENCODE,
+ (NULL), ("got head tag before preamble"));
+ enc->flow_return = GST_FLOW_ERROR;
+ return;
+push_error:
+ gst_caps_unref (caps);
+ /* fallthrough */
+alloc_error:
+ for (walk = headers; walk; walk = walk->next)
+ gst_buffer_unref (GST_BUFFER (walk->data));
+ g_list_free (headers);
+ return;
+}
+
+/* encode a CMML clip tag
+ * remove the start and end attributes (GstCmmlParser does this itself) and
+ * push the tag with the timestamp of its start attribute. If the tag has the
+ * end attribute, create a new empty clip and encode it.
+ */
+static void
+gst_cmml_enc_parse_tag_clip (GstCmmlEnc * enc, GstCmmlTagClip * clip)
+{
+ GstCmmlTagClip *prev_clip;
+ GstClockTime prev_clip_time = GST_CLOCK_TIME_NONE;
+
+ /* this can happen if there's a programming error (eg user forgets to set
+ * the start-time property) or if one of the gst_cmml_clock_time_from_*
+ * overflows in GstCmmlParser */
+ if (clip->start_time == GST_CLOCK_TIME_NONE) {
+ GST_ELEMENT_ERROR (enc, STREAM, ENCODE,
+ (NULL), ("invalid start time for clip (%s)", clip->id));
+ enc->flow_return = GST_FLOW_ERROR;
+
+ return;
+ }
+
+ /* get the previous clip's start time to encode the current granulepos */
+ prev_clip = gst_cmml_track_list_get_track_last_clip (enc->tracks,
+ (gchar *) clip->track);
+ if (prev_clip) {
+ prev_clip_time = prev_clip->start_time;
+ if (prev_clip_time > clip->start_time) {
+ GST_ELEMENT_ERROR (enc, STREAM, ENCODE,
+ (NULL), ("previous clip start time > current clip (%s) start time",
+ clip->id));
+ enc->flow_return = GST_FLOW_ERROR;
+ return;
+ }
+
+ /* we don't need the prev clip anymore */
+ gst_cmml_track_list_del_clip (enc->tracks, prev_clip);
+ }
+
+ /* add the current clip to the tracklist */
+ gst_cmml_track_list_add_clip (enc->tracks, clip);
+
+ enc->flow_return = gst_cmml_enc_push_clip (enc, clip, prev_clip_time);
+}
+
+static GstFlowReturn
+gst_cmml_enc_push_clip (GstCmmlEnc * enc, GstCmmlTagClip * clip,
+ GstClockTime prev_clip_time)
+{
+ GstFlowReturn res;
+ GstBuffer *buffer;
+ gchar *clip_string;
+ gint64 granulepos;
+
+ /* encode the clip */
+ clip_string =
+ (gchar *) gst_cmml_parser_tag_clip_to_string (enc->parser, clip);
+
+ res = gst_cmml_enc_new_buffer (enc,
+ (guchar *) clip_string, strlen (clip_string), &buffer);
+ g_free (clip_string);
+ if (res != GST_FLOW_OK)
+ goto done;
+
+ GST_INFO_OBJECT (enc, "encoding clip"
+ "(start-time: %" GST_TIME_FORMAT " end-time: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (clip->start_time), GST_TIME_ARGS (clip->end_time));
+
+ /* set the granulepos */
+ granulepos = gst_cmml_clock_time_to_granule (prev_clip_time, clip->start_time,
+ enc->granulerate_n, enc->granulerate_d, enc->granuleshift);
+ if (granulepos == -1) {
+ gst_buffer_unref (buffer);
+ goto granule_overflow;
+ }
+
+ GST_BUFFER_OFFSET (buffer) = clip->start_time;
+ GST_BUFFER_OFFSET_END (buffer) = granulepos;
+ GST_BUFFER_TIMESTAMP (buffer) = clip->start_time;
+
+ res = gst_cmml_enc_push (enc, buffer);
+ if (res != GST_FLOW_OK)
+ goto done;
+
+ if (clip->end_time != GST_CLOCK_TIME_NONE) {
+ /* create a new empty clip for the same cmml track starting at end_time
+ */
+ GObject *end_clip = g_object_new (GST_TYPE_CMML_TAG_CLIP,
+ "start-time", clip->end_time, "track", clip->track, NULL);
+
+ /* encode the empty end clip */
+ gst_cmml_enc_push_clip (enc, GST_CMML_TAG_CLIP (end_clip),
+ clip->start_time);
+ g_object_unref (end_clip);
+ }
+done:
+ return res;
+
+granule_overflow:
+ GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), ("granulepos overflow"));
+ return GST_FLOW_ERROR;
+}
+
+static GstFlowReturn
+gst_cmml_enc_push (GstCmmlEnc * enc, GstBuffer * buffer)
+{
+ GstFlowReturn res;
+
+ res = gst_pad_push (enc->srcpad, buffer);
+ if (res != GST_FLOW_OK)
+ GST_WARNING_OBJECT (enc, "push returned: %s", gst_flow_get_name (res));
+
+ return res;
+}
+
+static GstFlowReturn
+gst_cmml_enc_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GError *err = NULL;
+ GstCmmlEnc *enc = GST_CMML_ENC (GST_PAD_PARENT (pad));
+
+ /* the CMML handlers registered with enc->parser will override this when
+ * encoding/pushing the buffers downstream
+ */
+ enc->flow_return = GST_FLOW_OK;
+
+ if (!gst_cmml_parser_parse_chunk (enc->parser,
+ (gchar *) GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), &err)) {
+ GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), ("%s", err->message));
+ g_error_free (err);
+ enc->flow_return = GST_FLOW_ERROR;
+ }
+
+ gst_buffer_unref (buffer);
+ return enc->flow_return;
+}
+
+gboolean
+gst_cmml_enc_plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "cmmlenc", GST_RANK_NONE,
+ GST_TYPE_CMML_ENC))
+ return FALSE;
+
+ GST_DEBUG_CATEGORY_INIT (cmmlenc, "cmmlenc", 0,
+ "annodex cmml decoding element");
+
+ return TRUE;
+}
diff --git a/ext/annodex/gstcmmlenc.h b/ext/annodex/gstcmmlenc.h
new file mode 100644
index 0000000..4f28e4c
--- /dev/null
+++ b/ext/annodex/gstcmmlenc.h
@@ -0,0 +1,79 @@
+/*
+ * gstcmmlenc.h - GStreamer CMML encoder
+ * Copyright (C) 2005 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CMML_ENC_H__
+#define __GST_CMML_ENC_H__
+
+#define GST_TYPE_CMML_ENC (gst_cmml_enc_get_type())
+#define GST_CMML_ENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CMML_ENC, GstCmmlEnc))
+#define GST_CMML_ENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CMML_ENC, GstCmmlEncClass))
+#define GST_IS_CMML_ENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_CMML_ENC))
+#define GST_IS_CMML_ENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_CMML_ENC))
+#define GST_CMML_ENC_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_CMML_ENC, GstCmmlEncClass))
+
+#include <glib.h>
+#include <gst/gst.h>
+
+#include "gstcmmlparser.h"
+#include "gstcmmlutils.h"
+
+typedef struct _GstCmmlEnc GstCmmlEnc;
+typedef struct _GstCmmlEncClass GstCmmlEncClass;
+
+struct _GstCmmlEnc
+{
+ GstElement element;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ gint16 major;
+ gint16 minor;
+ gint64 granulerate_n;
+ gint64 granulerate_d;
+ gint8 granuleshift;
+
+ GstCmmlParser *parser;
+ gboolean streaming;
+ GHashTable *tracks;
+ GstFlowReturn flow_return;
+ guchar *preamble;
+ gboolean sent_headers;
+ gboolean sent_eos;
+};
+
+struct _GstCmmlEncClass
+{
+ GstElementClass parent_class;
+};
+
+GType gst_cmml_enc_get_type (void);
+
+gboolean gst_cmml_enc_plugin_init (GstPlugin * plugin);
+
+#endif /* __GST_CMML_ENC_H__ */
diff --git a/ext/annodex/gstcmmlparser.c b/ext/annodex/gstcmmlparser.c
new file mode 100644
index 0000000..0e2f7cd
--- /dev/null
+++ b/ext/annodex/gstcmmlparser.c
@@ -0,0 +1,648 @@
+/*
+ * gstcmmlparser.c - GStreamer CMML document parser
+ * Copyright (C) 2005 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <gst/gst.h>
+
+#include "gstcmmlparser.h"
+#include "gstannodex.h"
+#include "gstcmmlutils.h"
+
+GST_DEBUG_CATEGORY_STATIC (cmmlparser);
+#define GST_CAT_DEFAULT cmmlparser
+
+static void gst_cmml_parser_generic_error (void *ctx, const char *msg, ...);
+static xmlNodePtr gst_cmml_parser_new_node (GstCmmlParser * parser,
+ const gchar * name, ...);
+static void
+gst_cmml_parser_parse_start_element_ns (xmlParserCtxt * ctxt,
+ const xmlChar * name, const xmlChar * prefix, const xmlChar * URI,
+ int nb_preferences, const xmlChar ** namespaces,
+ int nb_attributes, int nb_defaulted, const xmlChar ** attributes);
+static void gst_cmml_parser_parse_end_element_ns (xmlParserCtxt * ctxt,
+ const xmlChar * name, const xmlChar * prefix, const xmlChar * URI);
+static void gst_cmml_parser_parse_processing_instruction (xmlParserCtxtPtr ctxt,
+ const xmlChar * target, const xmlChar * data);
+static void gst_cmml_parser_meta_to_string (GstCmmlParser * parser,
+ xmlNodePtr parent, GValueArray * meta);
+
+/* initialize the parser */
+void
+gst_cmml_parser_init (void)
+{
+ GST_DEBUG_CATEGORY_INIT (cmmlparser, "cmmlparser", 0, "annodex CMML parser");
+
+ xmlGenericError = gst_cmml_parser_generic_error;
+}
+
+/* create a new CMML parser
+ */
+GstCmmlParser *
+gst_cmml_parser_new (GstCmmlParserMode mode)
+{
+ GstCmmlParser *parser = g_malloc (sizeof (GstCmmlParser));
+
+ parser->mode = mode;
+ parser->context = xmlCreatePushParserCtxt (NULL, NULL,
+ NULL, 0, "cmml-bitstream");
+ xmlCtxtUseOptions (parser->context, XML_PARSE_NONET | XML_PARSE_NOERROR);
+ parser->context->_private = parser;
+ parser->context->sax->startElementNs =
+ (startElementNsSAX2Func) gst_cmml_parser_parse_start_element_ns;
+ parser->context->sax->endElementNs =
+ (endElementNsSAX2Func) gst_cmml_parser_parse_end_element_ns;
+ parser->context->sax->processingInstruction = (processingInstructionSAXFunc)
+ gst_cmml_parser_parse_processing_instruction;
+ parser->preamble_callback = NULL;
+ parser->cmml_end_callback = NULL;
+ parser->stream_callback = NULL;
+ parser->head_callback = NULL;
+ parser->clip_callback = NULL;
+ parser->user_data = NULL;
+
+ return parser;
+}
+
+/* free a CMML parser instance
+ */
+void
+gst_cmml_parser_free (GstCmmlParser * parser)
+{
+ if (parser) {
+ xmlFreeDoc (parser->context->myDoc);
+ xmlFreeParserCtxt (parser->context);
+ g_free (parser);
+ }
+}
+
+/* parse an xml chunk
+ *
+ * returns false if the xml is invalid
+ */
+gboolean
+gst_cmml_parser_parse_chunk (GstCmmlParser * parser,
+ const gchar * data, guint size, GError ** err)
+{
+ gint xmlres;
+
+ xmlres = xmlParseChunk (parser->context, data, size, 0);
+ if (xmlres != XML_ERR_OK) {
+ xmlErrorPtr xml_error = xmlCtxtGetLastError (parser->context);
+
+ GST_DEBUG ("Error occurred decoding chunk %s", data);
+ g_set_error (err,
+ GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, "%s", xml_error->message);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* convert an xmlNodePtr to a string
+ */
+static guchar *
+gst_cmml_parser_node_to_string (GstCmmlParser * parser, xmlNodePtr node)
+{
+ xmlBufferPtr xml_buffer;
+ xmlDocPtr doc;
+ guchar *str;
+
+ if (parser)
+ doc = parser->context->myDoc;
+ else
+ doc = NULL;
+
+ xml_buffer = xmlBufferCreate ();
+ xmlNodeDump (xml_buffer, doc, node, 0, 0);
+ str = xmlStrndup (xml_buffer->content, xml_buffer->use);
+ xmlBufferFree (xml_buffer);
+
+ return str;
+}
+
+guchar *
+gst_cmml_parser_tag_stream_to_string (GstCmmlParser * parser,
+ GstCmmlTagStream * stream)
+{
+ xmlNodePtr node;
+ xmlNodePtr import;
+ guchar *ret;
+
+ node = gst_cmml_parser_new_node (parser, "stream", NULL);
+ if (stream->timebase)
+ xmlSetProp (node, (xmlChar *) "timebase", stream->timebase);
+
+ if (stream->utc)
+ xmlSetProp (node, (xmlChar *) "utc", stream->utc);
+
+ if (stream->imports) {
+ gint i;
+ GValue *val;
+
+ for (i = 0; i < stream->imports->n_values; ++i) {
+ val = g_value_array_get_nth (stream->imports, i);
+ import = gst_cmml_parser_new_node (parser, "import",
+ "src", g_value_get_string (val), NULL);
+ xmlAddChild (node, import);
+ }
+ }
+
+ ret = gst_cmml_parser_node_to_string (parser, node);
+
+ xmlUnlinkNode (node);
+ xmlFreeNode (node);
+
+ return ret;
+}
+
+/* convert a GstCmmlTagHead to its string representation
+ */
+guchar *
+gst_cmml_parser_tag_head_to_string (GstCmmlParser * parser,
+ GstCmmlTagHead * head)
+{
+ xmlNodePtr node;
+ xmlNodePtr tmp;
+ guchar *ret;
+
+ node = gst_cmml_parser_new_node (parser, "head", NULL);
+ if (head->title) {
+ tmp = gst_cmml_parser_new_node (parser, "title", NULL);
+ xmlNodeSetContent (tmp, head->title);
+ xmlAddChild (node, tmp);
+ }
+
+ if (head->base) {
+ tmp = gst_cmml_parser_new_node (parser, "base", "uri", head->base, NULL);
+ xmlAddChild (node, tmp);
+ }
+
+ if (head->meta)
+ gst_cmml_parser_meta_to_string (parser, node, head->meta);
+
+ ret = gst_cmml_parser_node_to_string (parser, node);
+
+ xmlUnlinkNode (node);
+ xmlFreeNode (node);
+
+ return ret;
+}
+
+/* convert a GstCmmlTagClip to its string representation
+ */
+guchar *
+gst_cmml_parser_tag_clip_to_string (GstCmmlParser * parser,
+ GstCmmlTagClip * clip)
+{
+ xmlNodePtr node;
+ xmlNodePtr tmp;
+ guchar *ret;
+
+ node = gst_cmml_parser_new_node (parser, "clip",
+ "id", clip->id, "track", clip->track, NULL);
+ /* add the anchor element */
+ if (clip->anchor_href) {
+ tmp = gst_cmml_parser_new_node (parser, "a",
+ "href", clip->anchor_href, NULL);
+ if (clip->anchor_text)
+ xmlNodeSetContent (tmp, clip->anchor_text);
+
+ xmlAddChild (node, tmp);
+ }
+ /* add the img element */
+ if (clip->img_src) {
+ tmp = gst_cmml_parser_new_node (parser, "img",
+ "src", clip->img_src, "alt", clip->img_alt, NULL);
+
+ xmlAddChild (node, tmp);
+ }
+ /* add the desc element */
+ if (clip->desc_text) {
+ tmp = gst_cmml_parser_new_node (parser, "desc", NULL);
+ xmlNodeSetContent (tmp, clip->desc_text);
+
+ xmlAddChild (node, tmp);
+ }
+ /* add the meta elements */
+ if (clip->meta)
+ gst_cmml_parser_meta_to_string (parser, node, clip->meta);
+
+ if (parser->mode == GST_CMML_PARSER_DECODE) {
+ gchar *time_str;
+
+ time_str = gst_cmml_clock_time_to_npt (clip->start_time);
+ if (time_str == NULL)
+ goto fail;
+
+ xmlSetProp (node, (xmlChar *) "start", (xmlChar *) time_str);
+ g_free (time_str);
+
+ if (clip->end_time != GST_CLOCK_TIME_NONE) {
+ time_str = gst_cmml_clock_time_to_npt (clip->end_time);
+ if (time_str == NULL)
+ goto fail;
+
+ xmlSetProp (node, (xmlChar *) "end", (xmlChar *) time_str);
+ g_free (time_str);
+ }
+ }
+
+ ret = gst_cmml_parser_node_to_string (parser, node);
+
+ xmlUnlinkNode (node);
+ xmlFreeNode (node);
+
+ return ret;
+fail:
+ xmlUnlinkNode (node);
+ xmlFreeNode (node);
+ return NULL;
+}
+
+guchar *
+gst_cmml_parser_tag_object_to_string (GstCmmlParser * parser, GObject * tag)
+{
+ guchar *tag_string = NULL;
+ GType tag_type = G_OBJECT_TYPE (tag);
+
+ if (tag_type == GST_TYPE_CMML_TAG_STREAM)
+ tag_string = gst_cmml_parser_tag_stream_to_string (parser,
+ GST_CMML_TAG_STREAM (tag));
+ else if (tag_type == GST_TYPE_CMML_TAG_HEAD)
+ tag_string = gst_cmml_parser_tag_head_to_string (parser,
+ GST_CMML_TAG_HEAD (tag));
+ else if (tag_type == GST_TYPE_CMML_TAG_CLIP)
+ tag_string = gst_cmml_parser_tag_clip_to_string (parser,
+ GST_CMML_TAG_CLIP (tag));
+ else
+ g_warning ("could not convert object to cmml");
+
+ return tag_string;
+}
+
+/*** private section ***/
+
+/* create a new node
+ *
+ * helper to create a node and set its attributes
+ */
+static xmlNodePtr
+gst_cmml_parser_new_node (GstCmmlParser * parser, const gchar * name, ...)
+{
+ va_list args;
+ xmlNodePtr node;
+ xmlChar *prop_name, *prop_value;
+
+ node = xmlNewNode (NULL, (xmlChar *) name);
+
+ va_start (args, name);
+
+ prop_name = va_arg (args, xmlChar *);
+ while (prop_name != NULL) {
+ prop_value = va_arg (args, xmlChar *);
+ if (prop_value != NULL)
+ xmlSetProp (node, prop_name, prop_value);
+
+ prop_name = va_arg (args, xmlChar *);
+ }
+ va_end (args);
+
+ return node;
+}
+
+/* get the last node of the stream
+ *
+ * returns the last node at depth 1 (if any) or the root node
+ */
+static xmlNodePtr
+gst_cmml_parser_get_last_element (GstCmmlParser * parser)
+{
+ xmlNodePtr node;
+
+ node = xmlDocGetRootElement (parser->context->myDoc);
+ if (!node) {
+ g_warning ("no last cmml element");
+ return NULL;
+ }
+
+ if (node->children)
+ node = xmlGetLastChild (node);
+
+ return node;
+}
+
+static void
+gst_cmml_parser_parse_preamble (GstCmmlParser * parser,
+ const guchar * attributes)
+{
+ gchar *preamble;
+ gchar *element;
+ const gchar *version;
+ const gchar *encoding;
+ const gchar *standalone;
+ xmlDocPtr doc;
+
+ doc = parser->context->myDoc;
+
+ version = doc->version ? (gchar *) doc->version : "1.0";
+ encoding = doc->encoding ? (gchar *) doc->encoding : "UTF-8";
+ standalone = doc->standalone ? "yes" : "no";
+
+ preamble = g_strdup_printf ("<?xml version=\"%s\""
+ " encoding=\"%s\" standalone=\"%s\"?>\n"
+ "<!DOCTYPE cmml SYSTEM \"cmml.dtd\">\n", version, encoding, standalone);
+
+ if (attributes == NULL)
+ attributes = (guchar *) "";
+
+ if (parser->mode == GST_CMML_PARSER_ENCODE)
+ element = g_strdup_printf ("<?cmml %s?>", attributes);
+ else
+ element = g_strdup_printf ("<cmml %s>", attributes);
+
+ parser->preamble_callback (parser->user_data,
+ (guchar *) preamble, (guchar *) element);
+
+ g_free (preamble);
+ g_free (element);
+}
+
+/* parse the cmml stream tag */
+static void
+gst_cmml_parser_parse_stream (GstCmmlParser * parser, xmlNodePtr stream)
+{
+ GstCmmlTagStream *stream_tag;
+ GValue str_val = { 0 };
+ xmlNodePtr walk;
+ guchar *timebase;
+
+ g_value_init (&str_val, G_TYPE_STRING);
+
+ /* read the timebase and utc attributes */
+ timebase = xmlGetProp (stream, (xmlChar *) "timebase");
+ if (timebase == NULL)
+ timebase = (guchar *) g_strdup ("0");
+
+ stream_tag = g_object_new (GST_TYPE_CMML_TAG_STREAM,
+ "timebase", timebase, NULL);
+ g_free (timebase);
+
+ stream_tag->utc = xmlGetProp (stream, (xmlChar *) "utc");
+
+ /* walk the children nodes */
+ for (walk = stream->children; walk; walk = walk->next) {
+ /* for every import tag add its src attribute to stream_tag->imports */
+ if (!xmlStrcmp (walk->name, (xmlChar *) "import")) {
+ g_value_take_string (&str_val,
+ (gchar *) xmlGetProp (walk, (xmlChar *) "src"));
+
+ if (stream_tag->imports == NULL)
+ stream_tag->imports = g_value_array_new (0);
+
+ g_value_array_append (stream_tag->imports, &str_val);
+ }
+ }
+ g_value_unset (&str_val);
+
+ parser->stream_callback (parser->user_data, stream_tag);
+ g_object_unref (stream_tag);
+}
+
+/* parse the cmml head tag */
+static void
+gst_cmml_parser_parse_head (GstCmmlParser * parser, xmlNodePtr head)
+{
+ GstCmmlTagHead *head_tag;
+ xmlNodePtr walk;
+ GValue str_val = { 0 };
+
+ head_tag = g_object_new (GST_TYPE_CMML_TAG_HEAD, NULL);
+
+ g_value_init (&str_val, G_TYPE_STRING);
+
+ /* Parse the content of the node and setup the GST_TAG_CMML_HEAD tag.
+ * Create a GST_TAG_TITLE when we find the title element.
+ */
+ for (walk = head->children; walk; walk = walk->next) {
+ if (!xmlStrcmp (walk->name, (xmlChar *) "title")) {
+ head_tag->title = xmlNodeGetContent (walk);
+ } else if (!xmlStrcmp (walk->name, (xmlChar *) "base")) {
+ head_tag->base = xmlGetProp (walk, (xmlChar *) "uri");
+ } else if (!xmlStrcmp (walk->name, (xmlChar *) "meta")) {
+ if (head_tag->meta == NULL)
+ head_tag->meta = g_value_array_new (0);
+ /* add a pair name, content to the meta value array */
+ g_value_take_string (&str_val,
+ (gchar *) xmlGetProp (walk, (xmlChar *) "name"));
+ g_value_array_append (head_tag->meta, &str_val);
+ g_value_take_string (&str_val,
+ (gchar *) xmlGetProp (walk, (xmlChar *) "content"));
+ g_value_array_append (head_tag->meta, &str_val);
+ }
+ }
+ g_value_unset (&str_val);
+
+ parser->head_callback (parser->user_data, head_tag);
+ g_object_unref (head_tag);
+}
+
+/* parse a cmml clip tag */
+static void
+gst_cmml_parser_parse_clip (GstCmmlParser * parser, xmlNodePtr clip)
+{
+ GstCmmlTagClip *clip_tag;
+ GValue str_val = { 0 };
+ guchar *id, *track, *start, *end;
+ xmlNodePtr walk;
+ GstClockTime start_time = GST_CLOCK_TIME_NONE;
+ GstClockTime end_time = GST_CLOCK_TIME_NONE;
+
+ start = xmlGetProp (clip, (xmlChar *) "start");
+ if (parser->mode == GST_CMML_PARSER_ENCODE && start == NULL)
+ /* XXX: validate the document */
+ return;
+
+ id = xmlGetProp (clip, (xmlChar *) "id");
+ track = xmlGetProp (clip, (xmlChar *) "track");
+ end = xmlGetProp (clip, (xmlChar *) "end");
+
+ if (track == NULL)
+ track = (guchar *) g_strdup ("default");
+
+ if (start) {
+ if (!strncmp ((gchar *) start, "smpte", 5))
+ start_time = gst_cmml_clock_time_from_smpte ((gchar *) start);
+ else
+ start_time = gst_cmml_clock_time_from_npt ((gchar *) start);
+ }
+
+ if (end) {
+ if (!strncmp ((gchar *) end, "smpte", 5))
+ start_time = gst_cmml_clock_time_from_smpte ((gchar *) end);
+ else
+ end_time = gst_cmml_clock_time_from_npt ((gchar *) end);
+ }
+
+ clip_tag = g_object_new (GST_TYPE_CMML_TAG_CLIP, "id", id,
+ "track", track, "start-time", start_time, "end-time", end_time, NULL);
+
+ g_free (id);
+ g_free (track);
+ g_free (start);
+ g_free (end);
+
+ g_value_init (&str_val, G_TYPE_STRING);
+
+ /* parse the children */
+ for (walk = clip->children; walk; walk = walk->next) {
+ /* the clip is not empty */
+ clip_tag->empty = FALSE;
+
+ if (!xmlStrcmp (walk->name, (xmlChar *) "a")) {
+ clip_tag->anchor_href = xmlGetProp (walk, (xmlChar *) "href");
+ clip_tag->anchor_text = xmlNodeGetContent (walk);
+ } else if (!xmlStrcmp (walk->name, (xmlChar *) "img")) {
+ clip_tag->img_src = xmlGetProp (walk, (xmlChar *) "src");
+ clip_tag->img_alt = xmlGetProp (walk, (xmlChar *) "alt");
+ } else if (!xmlStrcmp (walk->name, (xmlChar *) "desc")) {
+ clip_tag->desc_text = xmlNodeGetContent (walk);
+ } else if (!xmlStrcmp (walk->name, (xmlChar *) "meta")) {
+ if (clip_tag->meta == NULL)
+ clip_tag->meta = g_value_array_new (0);
+ /* add a pair name, content to the meta value array */
+ g_value_take_string (&str_val,
+ (char *) xmlGetProp (walk, (xmlChar *) "name"));
+ g_value_array_append (clip_tag->meta, &str_val);
+ g_value_take_string (&str_val,
+ (char *) xmlGetProp (walk, (xmlChar *) "content"));
+ g_value_array_append (clip_tag->meta, &str_val);
+ }
+ }
+ g_value_unset (&str_val);
+
+ parser->clip_callback (parser->user_data, clip_tag);
+ g_object_unref (clip_tag);
+}
+
+void
+gst_cmml_parser_meta_to_string (GstCmmlParser * parser,
+ xmlNodePtr parent, GValueArray * array)
+{
+ gint i;
+ xmlNodePtr node;
+ GValue *name, *content;
+
+ for (i = 0; i < array->n_values - 1; i += 2) {
+ name = g_value_array_get_nth (array, i);
+ content = g_value_array_get_nth (array, i + 1);
+ node = gst_cmml_parser_new_node (parser, "meta",
+ "name", g_value_get_string (name),
+ "content", g_value_get_string (content), NULL);
+ xmlAddChild (parent, node);
+ }
+}
+
+static void
+gst_cmml_parser_generic_error (void *ctx, const char *msg, ...)
+{
+#ifndef GST_DISABLE_GST_DEBUG
+ va_list varargs;
+
+ va_start (varargs, msg);
+ gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_WARNING,
+ "", "", 0, NULL, msg, varargs);
+ va_end (varargs);
+#endif /* GST_DISABLE_GST_DEBUG */
+}
+
+/* sax handler called when an element start tag is found
+ * this is used to parse the cmml start tag
+ */
+static void
+gst_cmml_parser_parse_start_element_ns (xmlParserCtxt * ctxt,
+ const xmlChar * name, const xmlChar * prefix, const xmlChar * URI,
+ int nb_preferences, const xmlChar ** namespaces,
+ int nb_attributes, int nb_defaulted, const xmlChar ** attributes)
+{
+ GstCmmlParser *parser = (GstCmmlParser *) ctxt->_private;
+
+ xmlSAX2StartElementNs (ctxt, name, prefix, URI, nb_preferences, namespaces,
+ nb_attributes, nb_defaulted, attributes);
+
+ if (parser->mode == GST_CMML_PARSER_ENCODE)
+ if (!xmlStrcmp (name, (xmlChar *) "cmml"))
+ if (parser->preamble_callback)
+ /* FIXME: parse attributes */
+ gst_cmml_parser_parse_preamble (parser, NULL);
+}
+
+/* sax processing instruction handler
+ * used to parse the cmml processing instruction
+ */
+static void
+gst_cmml_parser_parse_processing_instruction (xmlParserCtxtPtr ctxt,
+ const xmlChar * target, const xmlChar * data)
+{
+ GstCmmlParser *parser = (GstCmmlParser *) ctxt->_private;
+
+ xmlSAX2ProcessingInstruction (ctxt, target, data);
+
+ if (parser->mode == GST_CMML_PARSER_DECODE)
+ if (!xmlStrcmp (target, (xmlChar *) "cmml"))
+ if (parser->preamble_callback)
+ gst_cmml_parser_parse_preamble (parser, data);
+}
+
+/* sax handler called when an xml end tag is found
+ * used to parse the stream, head and clip nodes
+ */
+static void
+gst_cmml_parser_parse_end_element_ns (xmlParserCtxt * ctxt,
+ const xmlChar * name, const xmlChar * prefix, const xmlChar * URI)
+{
+ xmlNodePtr node;
+ GstCmmlParser *parser = (GstCmmlParser *) ctxt->_private;
+
+ xmlSAX2EndElementNs (ctxt, name, prefix, URI);
+
+ if (!xmlStrcmp (name, (xmlChar *) "clip")) {
+ if (parser->clip_callback) {
+ node = gst_cmml_parser_get_last_element (parser);
+ gst_cmml_parser_parse_clip (parser, node);
+ }
+ } else if (!xmlStrcmp (name, (xmlChar *) "cmml")) {
+ if (parser->cmml_end_callback)
+ parser->cmml_end_callback (parser->user_data);
+ } else if (!xmlStrcmp (name, (xmlChar *) "stream")) {
+ if (parser->stream_callback) {
+ node = gst_cmml_parser_get_last_element (parser);
+ gst_cmml_parser_parse_stream (parser, node);
+ }
+ } else if (!xmlStrcmp (name, (xmlChar *) "head")) {
+ if (parser->head_callback) {
+ node = gst_cmml_parser_get_last_element (parser);
+ gst_cmml_parser_parse_head (parser, node);
+ }
+ }
+}
diff --git a/ext/annodex/gstcmmlparser.h b/ext/annodex/gstcmmlparser.h
new file mode 100644
index 0000000..89c2bff
--- /dev/null
+++ b/ext/annodex/gstcmmlparser.h
@@ -0,0 +1,92 @@
+/*
+ * gstcmmlparser.h - GStreamer CMML document parser
+ * Copyright (C) 2005 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CMML_PARSER_H__
+#define __GST_CMML_PARSER_H__
+
+#include <libxml/parser.h>
+#include <glib.h>
+
+#include "gstcmmltag.h"
+
+typedef struct _GstCmmlParser GstCmmlParser;
+typedef enum _GstCmmlParserMode GstCmmlParserMode;
+
+typedef void (*GstCmmlParserPreambleCallback) (void *user_data,
+ const guchar * xml_preamble, const guchar * cmml_attrs);
+
+typedef void (*GstCmmlParserCmmlEndCallback) (void *user_data);
+
+typedef void (*GstCmmlParserStreamCallback) (void *user_data,
+ GstCmmlTagStream * stream);
+
+typedef void (*GstCmmlParserHeadCallback) (void *user_data,
+ GstCmmlTagHead * head);
+
+typedef void (*GstCmmlParserClipCallback) (void *user_data,
+ GstCmmlTagClip * clip);
+
+enum _GstCmmlParserMode
+{
+ GST_CMML_PARSER_ENCODE,
+ GST_CMML_PARSER_DECODE
+};
+
+struct _GstCmmlParser
+{
+ GstCmmlParserMode mode;
+
+ xmlParserCtxtPtr context;
+
+ const gchar *preamble;
+ guint preamble_size;
+
+ void *user_data;
+ GstCmmlParserPreambleCallback preamble_callback;
+ GstCmmlParserStreamCallback stream_callback;
+ GstCmmlParserCmmlEndCallback cmml_end_callback;
+ GstCmmlParserHeadCallback head_callback;
+ GstCmmlParserClipCallback clip_callback;
+};
+
+void gst_cmml_parser_init (void);
+
+GstCmmlParser *gst_cmml_parser_new (GstCmmlParserMode mode);
+void gst_cmml_parser_free (GstCmmlParser * parser);
+
+gboolean gst_cmml_parser_parse_chunk (GstCmmlParser * parser,
+ const gchar * data, guint size, GError ** error);
+
+guchar *gst_cmml_parser_tag_stream_to_string (GstCmmlParser * parser,
+ GstCmmlTagStream * stream);
+
+guchar *gst_cmml_parser_tag_head_to_string (GstCmmlParser * parser,
+ GstCmmlTagHead * head);
+
+guchar *gst_cmml_parser_tag_clip_to_string (GstCmmlParser * parser,
+ GstCmmlTagClip * clip);
+
+guchar *gst_cmml_parser_tag_object_to_string (GstCmmlParser * parser,
+ GObject * tag);
+
+#endif /* __GST_CMML_PARSER_H__ */
diff --git a/ext/annodex/gstcmmltag.c b/ext/annodex/gstcmmltag.c
new file mode 100644
index 0000000..2cf5d5f
--- /dev/null
+++ b/ext/annodex/gstcmmltag.c
@@ -0,0 +1,579 @@
+/*
+ * gstcmmltags.c - GStreamer CMML tag support
+ * Copyright (C) 2005 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstcmmlparser.h"
+#include "gstcmmltag.h"
+#include "gstannodex.h"
+
+enum
+{
+ ARG_0,
+ GST_CMML_TAG_STREAM_TIMEBASE,
+ GST_CMML_TAG_STREAM_UTC,
+ GST_CMML_TAG_STREAM_IMPORTS,
+ GST_CMML_TAG_HEAD_TITLE,
+ GST_CMML_TAG_HEAD_BASE,
+ GST_CMML_TAG_HEAD_META,
+ GST_CMML_TAG_CLIP_EMPTY,
+ GST_CMML_TAG_CLIP_ID,
+ GST_CMML_TAG_CLIP_TRACK,
+ GST_CMML_TAG_CLIP_START_TIME,
+ GST_CMML_TAG_CLIP_END_TIME,
+ GST_CMML_TAG_CLIP_ANCHOR_HREF,
+ GST_CMML_TAG_CLIP_ANCHOR_TEXT,
+ GST_CMML_TAG_CLIP_IMG_SRC,
+ GST_CMML_TAG_CLIP_IMG_ALT,
+ GST_CMML_TAG_CLIP_DESC_TEXT,
+ GST_CMML_TAG_CLIP_META,
+};
+
+G_DEFINE_TYPE (GstCmmlTagStream, gst_cmml_tag_stream, G_TYPE_OBJECT);
+static void gst_cmml_tag_stream_finalize (GObject * object);
+static void gst_cmml_tag_stream_set_property (GObject * object,
+ guint property_id, const GValue * value, GParamSpec * pspec);
+static void gst_cmml_tag_stream_get_property (GObject * object,
+ guint property_id, GValue * value, GParamSpec * pspec);
+static void gst_cmml_tag_stream_value_from_string_value (const GValue * src,
+ GValue * dest);
+
+G_DEFINE_TYPE (GstCmmlTagHead, gst_cmml_tag_head, G_TYPE_OBJECT);
+static void gst_cmml_tag_head_finalize (GObject * object);
+static void gst_cmml_tag_head_set_property (GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_cmml_tag_head_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_cmml_tag_head_value_from_string_value (const GValue * src,
+ GValue * dest);
+
+G_DEFINE_TYPE (GstCmmlTagClip, gst_cmml_tag_clip, G_TYPE_OBJECT);
+static void gst_cmml_tag_clip_finalize (GObject * object);
+static void gst_cmml_tag_clip_set_property (GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_cmml_tag_clip_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec);
+
+static void gst_cmml_tag_clip_value_from_string_value (const GValue * src,
+ GValue * dest);
+
+static void set_object_on_value (GObject * object, GValue * dest);
+
+static const gchar default_preamble[] =
+ "<?xml version=\"1.0\" standalone=\"yes\"?>";
+
+/* Stream tag */
+static void
+gst_cmml_tag_stream_class_init (GstCmmlTagStreamClass * stream_class)
+{
+ GObjectClass *klass = G_OBJECT_CLASS (stream_class);
+
+ klass->set_property = gst_cmml_tag_stream_set_property;
+ klass->get_property = gst_cmml_tag_stream_get_property;
+ klass->finalize = gst_cmml_tag_stream_finalize;
+
+ g_object_class_install_property (klass, GST_CMML_TAG_STREAM_TIMEBASE,
+ g_param_spec_string ("base-time",
+ "Base time",
+ "Playback time (in seconds) of the first data packet",
+ "0", G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_STREAM_UTC,
+ g_param_spec_string ("calendar-base-time",
+ "Calendar base time",
+ "Date and wall-clock time (expressed as UTC time in the format "
+ "YYYYMMDDTHHMMSS.sssZ) associated with the base-time",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_STREAM_IMPORTS,
+ g_param_spec_value_array ("input-streams",
+ "Input streams",
+ "List of input streams that compose this bitstream",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_CMML_TAG_STREAM,
+ gst_cmml_tag_stream_value_from_string_value);
+}
+
+static void
+gst_cmml_tag_stream_init (GstCmmlTagStream * stream)
+{
+}
+
+static void
+gst_cmml_tag_stream_finalize (GObject * object)
+{
+ GstCmmlTagStream *stream = GST_CMML_TAG_STREAM (object);
+
+ g_free (stream->timebase);
+ g_free (stream->utc);
+ if (stream->imports)
+ g_value_array_free (stream->imports);
+
+ if (G_OBJECT_CLASS (gst_cmml_tag_stream_parent_class)->finalize)
+ G_OBJECT_CLASS (gst_cmml_tag_stream_parent_class)->finalize (object);
+}
+
+static void
+gst_cmml_tag_stream_set_property (GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstCmmlTagStream *stream = GST_CMML_TAG_STREAM (object);
+
+ switch (property_id) {
+ case GST_CMML_TAG_STREAM_TIMEBASE:
+ g_free (stream->timebase);
+ stream->timebase = (guchar *) g_value_dup_string (value);
+ break;
+ case GST_CMML_TAG_STREAM_UTC:
+ g_free (stream->utc);
+ stream->utc = (guchar *) g_value_dup_string (value);
+ break;
+ case GST_CMML_TAG_STREAM_IMPORTS:
+ {
+ GValueArray *va = g_value_get_boxed (value);
+
+ if (stream->imports)
+ g_value_array_free (stream->imports);
+ stream->imports = va != NULL ? g_value_array_copy (va) : NULL;
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+
+static void
+gst_cmml_tag_stream_value_from_string_value (const GValue * src, GValue * dest)
+{
+ GstCmmlParser *parser;
+ const gchar *str;
+ guint size;
+
+ parser = gst_cmml_parser_new (GST_CMML_PARSER_DECODE);
+ parser->user_data = dest;
+ parser->stream_callback = (GstCmmlParserStreamCallback) set_object_on_value;
+ gst_cmml_parser_parse_chunk (parser,
+ default_preamble, strlen (default_preamble), NULL);
+
+ str = g_value_get_string (src);
+ size = strlen (str);
+ gst_cmml_parser_parse_chunk (parser, str, size, NULL);
+
+ gst_cmml_parser_free (parser);
+}
+
+static void
+gst_cmml_tag_stream_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstCmmlTagStream *stream = GST_CMML_TAG_STREAM (object);
+
+ switch (property_id) {
+ case GST_CMML_TAG_STREAM_TIMEBASE:
+ g_value_set_string (value, (gchar *) stream->timebase);
+ break;
+ case GST_CMML_TAG_STREAM_UTC:
+ g_value_set_string (value, (gchar *) stream->utc);
+ break;
+ case GST_CMML_TAG_STREAM_IMPORTS:
+ g_value_set_boxed (value, stream->imports);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+/* Head tag */
+static void
+gst_cmml_tag_head_class_init (GstCmmlTagHeadClass * head_class)
+{
+ GObjectClass *klass = G_OBJECT_CLASS (head_class);
+
+ klass->set_property = gst_cmml_tag_head_set_property;
+ klass->get_property = gst_cmml_tag_head_get_property;
+ klass->finalize = gst_cmml_tag_head_finalize;
+
+ g_object_class_install_property (klass, GST_CMML_TAG_HEAD_TITLE,
+ g_param_spec_string ("title",
+ "Title",
+ "Title of the bitstream",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_HEAD_BASE,
+ g_param_spec_string ("base-uri",
+ "Base URI",
+ "Base URI of the bitstream. All relative URIs are relative to this",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_HEAD_META,
+ g_param_spec_value_array ("meta",
+ "Meta annotations",
+ "Meta annotations for the complete Annodex bitstream",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_CMML_TAG_HEAD,
+ gst_cmml_tag_head_value_from_string_value);
+}
+
+static void
+gst_cmml_tag_head_init (GstCmmlTagHead * head)
+{
+}
+
+static void
+gst_cmml_tag_head_finalize (GObject * object)
+{
+ GstCmmlTagHead *head = GST_CMML_TAG_HEAD (object);
+
+ g_free (head->title);
+ g_free (head->base);
+ if (head->meta)
+ g_value_array_free (head->meta);
+
+ if (G_OBJECT_CLASS (gst_cmml_tag_head_parent_class)->finalize)
+ G_OBJECT_CLASS (gst_cmml_tag_head_parent_class)->finalize (object);
+}
+
+static void
+gst_cmml_tag_head_set_property (GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstCmmlTagHead *head = GST_CMML_TAG_HEAD (object);
+
+ switch (property_id) {
+ case GST_CMML_TAG_HEAD_TITLE:
+ g_free (head->title);
+ head->title = (guchar *) g_value_dup_string (value);
+ break;
+ case GST_CMML_TAG_HEAD_BASE:
+ g_free (head->base);
+ head->base = (guchar *) g_value_dup_string (value);
+ break;
+ case GST_CMML_TAG_HEAD_META:
+ {
+ GValueArray *va = g_value_get_boxed (value);
+
+ if (head->meta)
+ g_value_array_free (head->meta);
+ head->meta = va != NULL ? g_value_array_copy (va) : NULL;
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+gst_cmml_tag_head_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstCmmlTagHead *head = GST_CMML_TAG_HEAD (object);
+
+ switch (property_id) {
+ case GST_CMML_TAG_HEAD_TITLE:
+ g_value_set_string (value, (gchar *) head->title);
+ break;
+ case GST_CMML_TAG_HEAD_BASE:
+ g_value_set_string (value, (gchar *) head->base);
+ break;
+ case GST_CMML_TAG_HEAD_META:
+ g_value_set_boxed (value, head->meta);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+gst_cmml_tag_head_value_from_string_value (const GValue * src, GValue * dest)
+{
+ GstCmmlParser *parser;
+ const gchar *str;
+ guint size;
+
+ parser = gst_cmml_parser_new (GST_CMML_PARSER_DECODE);
+ parser->user_data = dest;
+ parser->head_callback = (GstCmmlParserHeadCallback) set_object_on_value;
+ gst_cmml_parser_parse_chunk (parser,
+ default_preamble, strlen (default_preamble), NULL);
+
+ str = g_value_get_string (src);
+ size = strlen (str);
+ gst_cmml_parser_parse_chunk (parser, str, size, NULL);
+
+ gst_cmml_parser_free (parser);
+}
+
+/* Clip tag */
+static void
+gst_cmml_tag_clip_class_init (GstCmmlTagClipClass * clip_class)
+{
+ GObjectClass *klass = G_OBJECT_CLASS (clip_class);
+
+ klass->set_property = gst_cmml_tag_clip_set_property;
+ klass->get_property = gst_cmml_tag_clip_get_property;
+ klass->finalize = gst_cmml_tag_clip_finalize;
+
+ g_object_class_install_property (klass, GST_CMML_TAG_CLIP_EMPTY,
+ g_param_spec_boolean ("empty",
+ "Empty clip flag",
+ "An empty clip only marks the end of the previous clip",
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_CLIP_ID,
+ g_param_spec_string ("id",
+ "Clip id",
+ "Id of the clip", NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_CLIP_TRACK,
+ g_param_spec_string ("track",
+ "Track number",
+ "The track this clip belongs to",
+ "default",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_CLIP_START_TIME,
+ g_param_spec_uint64 ("start-time",
+ "Start time",
+ "The start time (in seconds) of the clip",
+ 0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_CLIP_END_TIME,
+ g_param_spec_uint64 ("end-time",
+ "End time",
+ "The end time (in seconds) of the clip (only set if extract-mode=true)",
+ 0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_CLIP_ANCHOR_HREF,
+ g_param_spec_string ("anchor-uri",
+ "Anchor URI",
+ "The location of a Web resource closely connected to the clip",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_CLIP_ANCHOR_TEXT,
+ g_param_spec_string ("anchor-text",
+ "Anchor text",
+ "A short description of the resource pointed by anchor-uri",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_CLIP_IMG_SRC,
+ g_param_spec_string ("img-uri",
+ "Image URI",
+ "The URI of a representative image for the clip",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_CLIP_IMG_ALT,
+ g_param_spec_string ("img-alt",
+ "Image alternative text",
+ "Alternative text to be displayed instead of the image "
+ "specified in img-uri", NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_CLIP_DESC_TEXT,
+ g_param_spec_string ("description",
+ "Description",
+ "A textual description of the content of the clip",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (klass, GST_CMML_TAG_CLIP_META,
+ g_param_spec_value_array ("meta",
+ "Meta annotations",
+ "Meta annotations for the clip",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_CMML_TAG_CLIP,
+ gst_cmml_tag_clip_value_from_string_value);
+}
+
+static void
+gst_cmml_tag_clip_init (GstCmmlTagClip * clip)
+{
+}
+
+static void
+gst_cmml_tag_clip_finalize (GObject * object)
+{
+ GstCmmlTagClip *clip = GST_CMML_TAG_CLIP (object);
+
+ g_free (clip->id);
+ g_free (clip->track);
+ g_free (clip->anchor_href);
+ g_free (clip->anchor_text);
+ g_free (clip->img_src);
+ g_free (clip->img_alt);
+ g_free (clip->desc_text);
+ if (clip->meta)
+ g_value_array_free (clip->meta);
+
+ if (G_OBJECT_CLASS (gst_cmml_tag_clip_parent_class)->finalize)
+ G_OBJECT_CLASS (gst_cmml_tag_clip_parent_class)->finalize (object);
+}
+
+static void
+gst_cmml_tag_clip_set_property (GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstCmmlTagClip *clip = GST_CMML_TAG_CLIP (object);
+
+ switch (property_id) {
+ case GST_CMML_TAG_CLIP_EMPTY:
+ clip->empty = g_value_get_boolean (value);
+ break;
+ case GST_CMML_TAG_CLIP_ID:
+ g_free (clip->id);
+ clip->id = (guchar *) g_value_dup_string (value);
+ break;
+ case GST_CMML_TAG_CLIP_TRACK:
+ g_free (clip->track);
+ clip->track = (guchar *) g_value_dup_string (value);
+ break;
+ case GST_CMML_TAG_CLIP_START_TIME:
+ clip->start_time = g_value_get_uint64 (value);
+ break;
+ case GST_CMML_TAG_CLIP_END_TIME:
+ clip->end_time = g_value_get_uint64 (value);
+ break;
+ case GST_CMML_TAG_CLIP_ANCHOR_HREF:
+ g_free (clip->anchor_href);
+ clip->anchor_href = (guchar *) g_value_dup_string (value);
+ break;
+ case GST_CMML_TAG_CLIP_ANCHOR_TEXT:
+ g_free (clip->anchor_text);
+ clip->anchor_text = (guchar *) g_value_dup_string (value);
+ break;
+ case GST_CMML_TAG_CLIP_IMG_SRC:
+ g_free (clip->img_src);
+ clip->img_src = (guchar *) g_value_dup_string (value);
+ break;
+ case GST_CMML_TAG_CLIP_IMG_ALT:
+ g_free (clip->img_alt);
+ clip->img_alt = (guchar *) g_value_dup_string (value);
+ break;
+ case GST_CMML_TAG_CLIP_DESC_TEXT:
+ g_free (clip->desc_text);
+ clip->desc_text = (guchar *) g_value_dup_string (value);
+ break;
+ case GST_CMML_TAG_CLIP_META:
+ {
+ GValueArray *va = (GValueArray *) g_value_get_boxed (value);
+
+ if (clip->meta)
+ g_value_array_free (clip->meta);
+
+ clip->meta = va != NULL ? g_value_array_copy (va) : NULL;
+
+ break;
+ }
+ }
+}
+
+static void
+gst_cmml_tag_clip_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstCmmlTagClip *clip = GST_CMML_TAG_CLIP (object);
+
+ switch (property_id) {
+ case GST_CMML_TAG_CLIP_EMPTY:
+ g_value_set_boolean (value, clip->empty);
+ break;
+ case GST_CMML_TAG_CLIP_ID:
+ g_value_set_string (value, (gchar *) clip->id);
+ break;
+ case GST_CMML_TAG_CLIP_TRACK:
+ g_value_set_string (value, (gchar *) clip->track);
+ break;
+ case GST_CMML_TAG_CLIP_START_TIME:
+ g_value_set_uint64 (value, clip->start_time);
+ break;
+ case GST_CMML_TAG_CLIP_END_TIME:
+ g_value_set_uint64 (value, clip->end_time);
+ break;
+ case GST_CMML_TAG_CLIP_ANCHOR_HREF:
+ g_value_set_string (value, (gchar *) clip->anchor_href);
+ break;
+ case GST_CMML_TAG_CLIP_ANCHOR_TEXT:
+ g_value_set_string (value, (gchar *) clip->anchor_text);
+ break;
+ case GST_CMML_TAG_CLIP_IMG_SRC:
+ g_value_set_string (value, (gchar *) clip->img_src);
+ break;
+ case GST_CMML_TAG_CLIP_IMG_ALT:
+ g_value_set_string (value, (gchar *) clip->img_alt);
+ break;
+ case GST_CMML_TAG_CLIP_DESC_TEXT:
+ g_value_set_string (value, (gchar *) clip->desc_text);
+ break;
+ case GST_CMML_TAG_CLIP_META:
+ g_value_set_boxed (value, clip->meta);
+ break;
+ }
+}
+
+static void
+gst_cmml_tag_clip_value_from_string_value (const GValue * src, GValue * dest)
+{
+ GstCmmlParser *parser;
+ const gchar *str;
+ guint size;
+
+ parser = gst_cmml_parser_new (GST_CMML_PARSER_DECODE);
+ parser->user_data = dest;
+ parser->clip_callback = (GstCmmlParserClipCallback) set_object_on_value;
+
+ gst_cmml_parser_parse_chunk (parser, default_preamble,
+ strlen (default_preamble), NULL);
+
+ str = g_value_get_string (src);
+ size = strlen (str);
+
+ gst_cmml_parser_parse_chunk (parser, str, size, NULL);
+
+ gst_cmml_parser_free (parser);
+}
+
+static void
+set_object_on_value (GObject * tag, GValue * dest)
+{
+ g_value_take_object (dest, tag);
+}
diff --git a/ext/annodex/gstcmmltag.h b/ext/annodex/gstcmmltag.h
new file mode 100644
index 0000000..e8c9bbb
--- /dev/null
+++ b/ext/annodex/gstcmmltag.h
@@ -0,0 +1,133 @@
+/*
+ * gstcmmltag.h - GStreamer annodex CMML tag support
+ * Copyright (C) 2005 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CMML_TAG_H__
+#define __GST_CMML_TAG_H__
+
+#include <gst/gst.h>
+
+/* GstCmmlTagStream */
+#define GST_TYPE_CMML_TAG_STREAM (gst_cmml_tag_stream_get_type ())
+#define GST_CMML_TAG_STREAM(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ GST_TYPE_CMML_TAG_STREAM, GstCmmlTagStream))
+#define GST_CMML_TAG_STREAM_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), \
+ GST_TYPE_CMML_TAG_STREAM, GstCmmlTagStreamClass))
+#define GST_CMML_TAG_STREAM_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ GST_TYPE_CMML_TAG_STREAM, GstCmmlTagStreamClass))
+
+/* GstCmmlTagHead */
+#define GST_TYPE_CMML_TAG_HEAD (gst_cmml_tag_head_get_type ())
+#define GST_CMML_TAG_HEAD(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CMML_TAG_HEAD, GstCmmlTagHead))
+#define GST_CMML_TAG_HEAD_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CMML_TAG_HEAD, GstCmmlTagHeadClass))
+#define GST_CMML_TAG_HEAD_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ GST_TYPE_CMML_TAG_HEAD, GstCmmlTagHeadClass))
+
+/* GstCmmlTagClip */
+#define GST_TYPE_CMML_TAG_CLIP (gst_cmml_tag_clip_get_type ())
+#define GST_CMML_TAG_CLIP(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CMML_TAG_CLIP, GstCmmlTagClip))
+#define GST_CMML_TAG_CLIP_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CMML_TAG_CLIP, GstCmmlTagClipClass))
+#define GST_CMML_TAG_CLIP_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ GST_TYPE_CMML_TAG_CLIP, GstCmmlTagClipClass))
+
+typedef struct _GstCmmlTagStream GstCmmlTagStream;
+typedef struct _GstCmmlTagStreamClass GstCmmlTagStreamClass;
+typedef struct _GstCmmlTagHead GstCmmlTagHead;
+typedef struct _GstCmmlTagHeadClass GstCmmlTagHeadClass;
+typedef struct _GstCmmlTagClip GstCmmlTagClip;
+typedef struct _GstCmmlTagClipClass GstCmmlTagClipClass;
+
+struct _GstCmmlTagStream {
+ GObject object;
+
+ guchar *timebase;
+ guchar *utc;
+
+ GValueArray *imports;
+};
+
+struct _GstCmmlTagStreamClass {
+ GObjectClass parent_class;
+};
+
+struct _GstCmmlTagHead {
+ GObject object;
+
+ guchar *title; /* title of the media */
+ guchar *base;
+ GValueArray *meta; /* metadata attached to the media.
+ * The elements are positioned in key-value
+ * pairs ie (key, content, key2, content2,
+ * ...)
+ */
+};
+
+struct _GstCmmlTagHeadClass {
+ GObjectClass parent_class;
+};
+
+struct _GstCmmlTagClip {
+ GObject object;
+
+ gboolean empty; /* empty flag. An empty clip marks the
+ * end of the previous clip.
+ */
+
+ guchar *id; /* clip id */
+ guchar *track; /* clip track */
+
+ GstClockTime start_time; /* clip start time */
+ GstClockTime end_time; /* clip end time */
+
+ guchar *anchor_href; /* anchor href URI */
+ guchar *anchor_text; /* anchor text */
+
+ guchar *img_src; /* image URI */
+ guchar *img_alt; /* image alternative text */
+
+ guchar *desc_text; /* clip description */
+
+ GValueArray *meta; /* metadata attached to the clip
+ * The elements are positioned in key-value
+ * pairs ie (key, content, key2, content2,
+ * ...)
+ */
+};
+
+struct _GstCmmlTagClipClass {
+ GObjectClass parent_class;
+};
+
+GType gst_cmml_tag_stream_get_type (void);
+GType gst_cmml_tag_head_get_type (void);
+GType gst_cmml_tag_clip_get_type (void);
+
+#endif /* __GST_CMML_TAG_H__ */
diff --git a/ext/annodex/gstcmmlutils.c b/ext/annodex/gstcmmlutils.c
new file mode 100644
index 0000000..a66b3f0
--- /dev/null
+++ b/ext/annodex/gstcmmlutils.c
@@ -0,0 +1,388 @@
+/*
+ * gstcmmlutils.c - GStreamer CMML utility functions
+ * Copyright (C) 2005 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gstcmmlutils.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef struct
+{
+ GList *clips;
+ gpointer user_data;
+} GstCmmlTrack;
+
+GstClockTime
+gst_cmml_clock_time_from_npt (const gchar * time)
+{
+ GstClockTime res;
+ gint fields;
+ gint hours = 0;
+ gint minutes = 0;
+ gint seconds = 0;
+ gint mseconds = 0;
+ GstClockTime hours_t = 0, seconds_t = 0;
+
+ if (!strncmp (time, "npt:", 4))
+ time += 4;
+
+ /* parse npt-hhmmss */
+ fields = sscanf (time, "%d:%d:%d.%d", &hours, &minutes, &seconds, &mseconds);
+ if (fields == 4) {
+ if (hours < 0 || (guint) minutes > 59 || (guint) seconds > 59)
+ goto bad_input;
+
+ hours_t = gst_util_uint64_scale (hours, GST_SECOND * 3600, 1);
+ if (hours_t == G_MAXUINT64)
+ goto overflow;
+
+ seconds_t = seconds * GST_SECOND;
+ } else {
+ guint64 u64seconds;
+
+ /* parse npt-sec */
+ hours_t = 0;
+ minutes = 0;
+ fields = sscanf (time, "%" G_GUINT64_FORMAT ".%d", &u64seconds, &mseconds);
+ if (seconds < 0)
+ goto bad_input;
+
+ seconds_t = gst_util_uint64_scale_int (u64seconds, GST_SECOND, 1);
+ if (seconds_t == G_MAXUINT64)
+ goto overflow;
+ }
+
+ if ((guint) mseconds > 999)
+ goto bad_input;
+
+ res = (minutes * 60) * GST_SECOND + mseconds * GST_MSECOND;
+ if (G_MAXUINT64 - hours_t - seconds_t < res)
+ goto overflow;
+
+ res += hours_t + seconds_t;
+
+ return res;
+
+bad_input:
+overflow:
+ return GST_CLOCK_TIME_NONE;
+}
+
+GstClockTime
+gst_cmml_clock_time_from_smpte (const gchar * time)
+{
+ GstClockTime res;
+ GstClockTime hours_t;
+ gint hours, minutes, seconds;
+ gdouble framerate;
+ gfloat frames;
+ gint fields;
+
+ if (!strncmp (time, "smpte-24:", 9)) {
+ framerate = 24.0;
+ time += 9;
+ } else if (!strncmp (time, "smpte-24-drop:", 14)) {
+ framerate = 23.976;
+ time += 14;
+ } else if (!strncmp (time, "smpte-25:", 9)) {
+ framerate = 25.0;
+ time += 9;
+ } else if (!strncmp (time, "smpte-30:", 9)) {
+ framerate = 30.0;
+ time += 9;
+ } else if (!strncmp (time, "smpte-30-drop:", 14)) {
+ framerate = 29.976;
+ time += 14;
+ } else if (!strncmp (time, "smpte-50:", 9)) {
+ framerate = 50.0;
+ time += 9;
+ } else if (!strncmp (time, "smpte-60:", 9)) {
+ framerate = 60.0;
+ time += 9;
+ } else if (!strncmp (time, "smpte-60-drop:", 14)) {
+ framerate = 59.94;
+ time += 14;
+ } else {
+ return GST_CLOCK_TIME_NONE;
+ }
+
+ fields = sscanf (time, "%d:%d:%d:%f", &hours, &minutes, &seconds, &frames);
+ if (fields == 4) {
+ if (hours < 0 || (guint) minutes > 59 || (guint) seconds > 59 ||
+ frames < 0 || frames > ceil (framerate)) {
+ res = GST_CLOCK_TIME_NONE;
+ } else {
+ hours_t = gst_util_uint64_scale (hours, GST_SECOND * 3600, 1);
+ if (hours_t == G_MAXUINT64)
+ goto overflow;
+
+ res = ((minutes * 60) + seconds + (frames / framerate))
+ * GST_SECOND;
+ if (G_MAXUINT64 - hours_t < res)
+ goto overflow;
+
+ res = hours_t + res;
+ }
+ } else {
+ res = GST_CLOCK_TIME_NONE;
+ }
+
+ return res;
+overflow:
+ return GST_CLOCK_TIME_NONE;
+}
+
+gchar *
+gst_cmml_clock_time_to_npt (const GstClockTime time)
+{
+ guint seconds, hours, minutes, mseconds;
+ gchar *res;
+
+ g_return_val_if_fail (time != GST_CLOCK_TIME_NONE, NULL);
+
+ hours = time / (GST_SECOND * 3600);
+ minutes = (time / ((GST_SECOND * 60)) % 60);
+ seconds = (time / GST_SECOND) % 60;
+ mseconds = (time % GST_SECOND) / GST_MSECOND;
+
+ if (mseconds < 100)
+ mseconds *= 10;
+
+ res = g_strdup_printf ("%u:%02u:%02u.%03u",
+ hours, minutes, seconds, mseconds);
+
+ return res;
+}
+
+gint64
+gst_cmml_clock_time_to_granule (GstClockTime prev_time,
+ GstClockTime current_time, gint64 granulerate_n, gint64 granulerate_d,
+ guint8 granuleshift)
+{
+ guint64 keyindex, keyoffset, granulepos, maxoffset;
+ gint64 granulerate;
+
+ g_return_val_if_fail (granulerate_d != 0, -1);
+ g_return_val_if_fail (granuleshift > 0, -1);
+ g_return_val_if_fail (granuleshift <= 64, -1);
+
+ if (prev_time == GST_CLOCK_TIME_NONE)
+ prev_time = 0;
+
+ if (prev_time > current_time)
+ return -1;
+
+ /* GST_SECOND / (granulerate_n / granulerate_d) */
+ granulerate = gst_util_uint64_scale (GST_SECOND,
+ granulerate_d, granulerate_n);
+
+ prev_time = prev_time / granulerate;
+
+ /* granuleshift == 64 should be a << 0 shift, which is defined */
+ maxoffset = ((guint64) 1 << (64 - granuleshift)) - 1;
+ if (prev_time > maxoffset)
+ /* we need more than 64 - granuleshift bits to encode prev_time */
+ goto overflow;
+
+ keyindex = prev_time << granuleshift;
+
+ keyoffset = (current_time / granulerate) - prev_time;
+ /* make sure we don't shift to the limits of the types as this is undefined. */
+ if (granuleshift == 64)
+ maxoffset = G_MAXUINT64;
+ else
+ maxoffset = ((guint64) 1 << granuleshift) - 1;
+
+ if (keyoffset > maxoffset)
+ /* we need more than granuleshift bits to encode prev_time - current_time */
+ goto overflow;
+
+ granulepos = keyindex + keyoffset;
+
+ return granulepos;
+
+overflow:
+ return -1;
+}
+
+/* track list */
+GHashTable *
+gst_cmml_track_list_new (void)
+{
+ return g_hash_table_new (g_str_hash, g_str_equal);
+}
+
+static gboolean
+gst_cmml_track_list_destroy_track (gchar * key,
+ GstCmmlTrack * track, gpointer user_data)
+{
+ GList *walk;
+
+ for (walk = track->clips; walk; walk = g_list_next (walk))
+ g_object_unref (G_OBJECT (walk->data));
+
+ g_free (key);
+ g_list_free (track->clips);
+ g_free (track);
+
+ return TRUE;
+}
+
+void
+gst_cmml_track_list_destroy (GHashTable * tracks)
+{
+ g_hash_table_foreach_remove (tracks,
+ (GHRFunc) gst_cmml_track_list_destroy_track, NULL);
+ g_hash_table_destroy (tracks);
+}
+
+static gint
+gst_cmml_track_list_compare_clips (GstCmmlTagClip * a, GstCmmlTagClip * b)
+{
+ if (a->start_time < b->start_time)
+ return -1;
+
+ return 1;
+}
+
+void
+gst_cmml_track_list_add_clip (GHashTable * tracks, GstCmmlTagClip * clip)
+{
+ gpointer key, value;
+ GstCmmlTrack *track;
+ gchar *track_name;
+
+ g_return_if_fail (clip->track != NULL);
+
+ if (g_hash_table_lookup_extended (tracks, clip->track, &key, &value)) {
+ track_name = (gchar *) key;
+ track = (GstCmmlTrack *) value;
+ } else {
+ track_name = g_strdup ((gchar *) clip->track);
+ track = g_new0 (GstCmmlTrack, 1);
+ g_hash_table_insert (tracks, track_name, track);
+ }
+
+ /* add clip to the tracklist */
+ track->clips = g_list_insert_sorted (track->clips, g_object_ref (clip),
+ (GCompareFunc) gst_cmml_track_list_compare_clips);
+}
+
+gboolean
+gst_cmml_track_list_del_clip (GHashTable * tracks, GstCmmlTagClip * clip)
+{
+ GstCmmlTrack *track;
+ GList *link;
+ gboolean res = FALSE;
+
+ g_return_val_if_fail (clip->track != NULL, FALSE);
+
+ track = g_hash_table_lookup (tracks, clip->track);
+ if (track) {
+ link = g_list_find (track->clips, clip);
+ if (link) {
+ g_object_unref (G_OBJECT (link->data));
+ track->clips = g_list_delete_link (track->clips, link);
+ res = TRUE;
+ }
+ }
+
+ return res;
+}
+
+gboolean
+gst_cmml_track_list_has_clip (GHashTable * tracks, GstCmmlTagClip * clip)
+{
+ GstCmmlTrack *track;
+ GList *walk;
+ GstCmmlTagClip *tmp;
+ gboolean res = FALSE;
+
+ track = g_hash_table_lookup (tracks, (gchar *) clip->track);
+ if (track) {
+ for (walk = track->clips; walk; walk = g_list_next (walk)) {
+ tmp = GST_CMML_TAG_CLIP (walk->data);
+ if (tmp->start_time == clip->start_time) {
+ res = TRUE;
+ break;
+ }
+ }
+ }
+
+ return res;
+}
+
+static gboolean
+gst_cmml_track_list_merge_track (gchar * track_name,
+ GstCmmlTrack * track, GList ** list)
+{
+ GList *walk;
+ GstCmmlTagClip *cur;
+
+ for (walk = track->clips; walk; walk = g_list_next (walk)) {
+ cur = GST_CMML_TAG_CLIP (walk->data);
+ *list = g_list_insert_sorted (*list, cur,
+ (GCompareFunc) gst_cmml_track_list_compare_clips);
+ }
+
+ return TRUE;
+}
+
+GList *
+gst_cmml_track_list_get_track_clips (GHashTable * tracks,
+ const gchar * track_name)
+{
+ GstCmmlTrack *track;
+
+ g_return_val_if_fail (track_name != NULL, NULL);
+
+ track = g_hash_table_lookup (tracks, track_name);
+ return track ? track->clips : NULL;
+}
+
+GList *
+gst_cmml_track_list_get_clips (GHashTable * tracks)
+{
+ GList *list = NULL;
+
+ g_hash_table_foreach (tracks,
+ (GHFunc) gst_cmml_track_list_merge_track, &list);
+ return list;
+}
+
+GstCmmlTagClip *
+gst_cmml_track_list_get_track_last_clip (GHashTable * tracks,
+ const gchar * track_name)
+{
+ GstCmmlTrack *track;
+ GList *res = NULL;
+
+ g_return_val_if_fail (track_name != NULL, NULL);
+
+ track = g_hash_table_lookup (tracks, track_name);
+ if (track && track->clips)
+ res = g_list_last (track->clips);
+
+ return res ? GST_CMML_TAG_CLIP (res->data) : NULL;
+}
diff --git a/ext/annodex/gstcmmlutils.h b/ext/annodex/gstcmmlutils.h
new file mode 100644
index 0000000..5aa2416
--- /dev/null
+++ b/ext/annodex/gstcmmlutils.h
@@ -0,0 +1,53 @@
+/*
+ * gstcmmlutils.h - GStreamer CMML utility functions
+ * Copyright (C) 2005 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CMML_CLOCK_TIME_H__
+#define __GST_CMML_CLOCK_TIME_H__
+
+#include <gst/gst.h>
+#include "gstcmmltag.h"
+
+/* time utils */
+GstClockTime gst_cmml_clock_time_from_npt (const gchar * time);
+GstClockTime gst_cmml_clock_time_from_smpte (const gchar * time);
+gchar * gst_cmml_clock_time_to_npt (const GstClockTime time);
+gint64 gst_cmml_clock_time_to_granule (GstClockTime prev_time,
+ GstClockTime current_time, gint64 granulerate_n, gint64 granulerate_d,
+ guint8 granuleshift);
+
+/* tracklist */
+GHashTable * gst_cmml_track_list_new (void);
+void gst_cmml_track_list_destroy (GHashTable * tracks);
+void gst_cmml_track_list_add_clip (GHashTable * tracks, GstCmmlTagClip * clip);
+gboolean gst_cmml_track_list_del_clip (GHashTable * tracks,
+ GstCmmlTagClip * clip);
+gboolean gst_cmml_track_list_has_clip (GHashTable * tracks,
+ GstCmmlTagClip * clip);
+GstCmmlTagClip * gst_cmml_track_list_get_track_last_clip (GHashTable * tracks,
+ const gchar * track_name);
+GList * gst_cmml_track_list_get_track_clips (GHashTable * tracks,
+ const gchar * track_name);
+GList * gst_cmml_track_list_get_clips (GHashTable * tracks);
+void gst_cmml_track_list_set_track_data (GHashTable * tracks, gpointer data);
+gpointer gst_cmml_track_list_get_track_data (GHashTable * tracks);
+#endif /* __GST_CMML_CLOCK_TIME_H__ */
diff --git a/ext/cairo/Makefile.am b/ext/cairo/Makefile.am
new file mode 100644
index 0000000..7fa8fdc
--- /dev/null
+++ b/ext/cairo/Makefile.am
@@ -0,0 +1,45 @@
+plugin_LTLIBRARIES = libgstcairo.la
+
+if USE_CAIRO_GOBJECT
+glib_enum_define = GST_CAIRO
+glib_gen_prefix = gst_cairo
+glib_gen_basename = gstcairo
+
+include $(top_srcdir)/common/gst-glib-gen.mak
+
+built_sources = gstcairo-marshal.c
+built_headers = gstcairo-marshal.h
+
+BUILT_SOURCES = $(built_sources) $(built_headers)
+
+gstcairo_gobject_dep_sources = gstcairooverlay.c
+gstcairo_gobject_dep_headers = gstcairooverlay.h
+
+CLEANFILES = $(BUILT_SOURCES)
+endif
+
+noinst_HEADERS = \
+ gsttimeoverlay.h \
+ gsttextoverlay.h \
+ gstcairorender.h \
+ $(gstcairo_gobject_dep_headers)
+libgstcairo_la_SOURCES = \
+ gstcairo.c \
+ gsttimeoverlay.c \
+ gsttextoverlay.c \
+ gstcairorender.c \
+ $(gstcairo_gobject_dep_sources)
+nodist_libgstcairo_la_SOURCES = \
+ $(built_sources)
+libgstcairo_la_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) $(CAIRO_CFLAGS) $(CAIRO_GOBJECT_CFLAGS)
+libgstcairo_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) $(GST_LIBS) $(CAIRO_LIBS) $(CAIRO_GOBJECT_LIBS) $(LIBM)
+libgstcairo_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstcairo_la_LIBTOOLFLAGS = --tag=disable-static
+
+EXTRA_DIST = gstcairo-marshal.list
+
diff --git a/ext/cairo/Makefile.in b/ext/cairo/Makefile.in
new file mode 100644
index 0000000..84b71b4
--- /dev/null
+++ b/ext/cairo/Makefile.in
@@ -0,0 +1,942 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# these are the variables your Makefile.am should set
+# the example is based on the colorbalance interface
+
+#glib_enum_headers=$(colorbalance_headers)
+#glib_enum_define=GST_COLOR_BALANCE
+#glib_gen_prefix=gst_color_balance
+#glib_gen_basename=colorbalance
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(am__noinst_HEADERS_DIST) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(top_srcdir)/common/gst-glib-gen.mak
+subdir = ext/cairo
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstcairo_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am__libgstcairo_la_SOURCES_DIST = gstcairo.c gsttimeoverlay.c \
+ gsttextoverlay.c gstcairorender.c gstcairooverlay.c
+@USE_CAIRO_GOBJECT_TRUE@am__objects_1 = \
+@USE_CAIRO_GOBJECT_TRUE@ libgstcairo_la-gstcairooverlay.lo
+am_libgstcairo_la_OBJECTS = libgstcairo_la-gstcairo.lo \
+ libgstcairo_la-gsttimeoverlay.lo \
+ libgstcairo_la-gsttextoverlay.lo \
+ libgstcairo_la-gstcairorender.lo $(am__objects_1)
+@USE_CAIRO_GOBJECT_TRUE@am__objects_2 = \
+@USE_CAIRO_GOBJECT_TRUE@ libgstcairo_la-gstcairo-marshal.lo
+nodist_libgstcairo_la_OBJECTS = $(am__objects_2)
+libgstcairo_la_OBJECTS = $(am_libgstcairo_la_OBJECTS) \
+ $(nodist_libgstcairo_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstcairo_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstcairo_la_CFLAGS) $(CFLAGS) \
+ $(libgstcairo_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstcairo_la_SOURCES) $(nodist_libgstcairo_la_SOURCES)
+DIST_SOURCES = $(am__libgstcairo_la_SOURCES_DIST)
+am__noinst_HEADERS_DIST = gsttimeoverlay.h gsttextoverlay.h \
+ gstcairorender.h gstcairooverlay.h
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstcairo.la
+@USE_CAIRO_GOBJECT_TRUE@glib_enum_define = GST_CAIRO
+@USE_CAIRO_GOBJECT_TRUE@glib_gen_prefix = gst_cairo
+@USE_CAIRO_GOBJECT_TRUE@glib_gen_basename = gstcairo
+@USE_CAIRO_GOBJECT_TRUE@enum_headers = $(foreach h,$(glib_enum_headers),\n\#include \"$(h)\")
+@USE_CAIRO_GOBJECT_TRUE@built_sources = gstcairo-marshal.c
+@USE_CAIRO_GOBJECT_TRUE@built_headers = gstcairo-marshal.h
+@USE_CAIRO_GOBJECT_TRUE@BUILT_SOURCES = $(built_sources) $(built_headers)
+@USE_CAIRO_GOBJECT_TRUE@gstcairo_gobject_dep_sources = gstcairooverlay.c
+@USE_CAIRO_GOBJECT_TRUE@gstcairo_gobject_dep_headers = gstcairooverlay.h
+@USE_CAIRO_GOBJECT_TRUE@CLEANFILES = $(BUILT_SOURCES)
+noinst_HEADERS = \
+ gsttimeoverlay.h \
+ gsttextoverlay.h \
+ gstcairorender.h \
+ $(gstcairo_gobject_dep_headers)
+
+libgstcairo_la_SOURCES = \
+ gstcairo.c \
+ gsttimeoverlay.c \
+ gsttextoverlay.c \
+ gstcairorender.c \
+ $(gstcairo_gobject_dep_sources)
+
+nodist_libgstcairo_la_SOURCES = \
+ $(built_sources)
+
+libgstcairo_la_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) $(CAIRO_CFLAGS) $(CAIRO_GOBJECT_CFLAGS)
+
+libgstcairo_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) $(GST_LIBS) $(CAIRO_LIBS) $(CAIRO_GOBJECT_LIBS) $(LIBM)
+
+libgstcairo_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstcairo_la_LIBTOOLFLAGS = --tag=disable-static
+EXTRA_DIST = gstcairo-marshal.list
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common/gst-glib-gen.mak $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/cairo/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/cairo/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+$(top_srcdir)/common/gst-glib-gen.mak:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstcairo.la: $(libgstcairo_la_OBJECTS) $(libgstcairo_la_DEPENDENCIES) $(EXTRA_libgstcairo_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstcairo_la_LINK) -rpath $(plugindir) $(libgstcairo_la_OBJECTS) $(libgstcairo_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstcairo_la-gstcairo-marshal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstcairo_la-gstcairo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstcairo_la-gstcairooverlay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstcairo_la-gstcairorender.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstcairo_la-gsttextoverlay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstcairo_la-gsttimeoverlay.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstcairo_la-gstcairo.lo: gstcairo.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcairo_la_CFLAGS) $(CFLAGS) -MT libgstcairo_la-gstcairo.lo -MD -MP -MF $(DEPDIR)/libgstcairo_la-gstcairo.Tpo -c -o libgstcairo_la-gstcairo.lo `test -f 'gstcairo.c' || echo '$(srcdir)/'`gstcairo.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstcairo_la-gstcairo.Tpo $(DEPDIR)/libgstcairo_la-gstcairo.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstcairo.c' object='libgstcairo_la-gstcairo.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcairo_la_CFLAGS) $(CFLAGS) -c -o libgstcairo_la-gstcairo.lo `test -f 'gstcairo.c' || echo '$(srcdir)/'`gstcairo.c
+
+libgstcairo_la-gsttimeoverlay.lo: gsttimeoverlay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcairo_la_CFLAGS) $(CFLAGS) -MT libgstcairo_la-gsttimeoverlay.lo -MD -MP -MF $(DEPDIR)/libgstcairo_la-gsttimeoverlay.Tpo -c -o libgstcairo_la-gsttimeoverlay.lo `test -f 'gsttimeoverlay.c' || echo '$(srcdir)/'`gsttimeoverlay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstcairo_la-gsttimeoverlay.Tpo $(DEPDIR)/libgstcairo_la-gsttimeoverlay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gsttimeoverlay.c' object='libgstcairo_la-gsttimeoverlay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcairo_la_CFLAGS) $(CFLAGS) -c -o libgstcairo_la-gsttimeoverlay.lo `test -f 'gsttimeoverlay.c' || echo '$(srcdir)/'`gsttimeoverlay.c
+
+libgstcairo_la-gsttextoverlay.lo: gsttextoverlay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcairo_la_CFLAGS) $(CFLAGS) -MT libgstcairo_la-gsttextoverlay.lo -MD -MP -MF $(DEPDIR)/libgstcairo_la-gsttextoverlay.Tpo -c -o libgstcairo_la-gsttextoverlay.lo `test -f 'gsttextoverlay.c' || echo '$(srcdir)/'`gsttextoverlay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstcairo_la-gsttextoverlay.Tpo $(DEPDIR)/libgstcairo_la-gsttextoverlay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gsttextoverlay.c' object='libgstcairo_la-gsttextoverlay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcairo_la_CFLAGS) $(CFLAGS) -c -o libgstcairo_la-gsttextoverlay.lo `test -f 'gsttextoverlay.c' || echo '$(srcdir)/'`gsttextoverlay.c
+
+libgstcairo_la-gstcairorender.lo: gstcairorender.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcairo_la_CFLAGS) $(CFLAGS) -MT libgstcairo_la-gstcairorender.lo -MD -MP -MF $(DEPDIR)/libgstcairo_la-gstcairorender.Tpo -c -o libgstcairo_la-gstcairorender.lo `test -f 'gstcairorender.c' || echo '$(srcdir)/'`gstcairorender.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstcairo_la-gstcairorender.Tpo $(DEPDIR)/libgstcairo_la-gstcairorender.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstcairorender.c' object='libgstcairo_la-gstcairorender.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcairo_la_CFLAGS) $(CFLAGS) -c -o libgstcairo_la-gstcairorender.lo `test -f 'gstcairorender.c' || echo '$(srcdir)/'`gstcairorender.c
+
+libgstcairo_la-gstcairooverlay.lo: gstcairooverlay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcairo_la_CFLAGS) $(CFLAGS) -MT libgstcairo_la-gstcairooverlay.lo -MD -MP -MF $(DEPDIR)/libgstcairo_la-gstcairooverlay.Tpo -c -o libgstcairo_la-gstcairooverlay.lo `test -f 'gstcairooverlay.c' || echo '$(srcdir)/'`gstcairooverlay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstcairo_la-gstcairooverlay.Tpo $(DEPDIR)/libgstcairo_la-gstcairooverlay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstcairooverlay.c' object='libgstcairo_la-gstcairooverlay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcairo_la_CFLAGS) $(CFLAGS) -c -o libgstcairo_la-gstcairooverlay.lo `test -f 'gstcairooverlay.c' || echo '$(srcdir)/'`gstcairooverlay.c
+
+libgstcairo_la-gstcairo-marshal.lo: gstcairo-marshal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcairo_la_CFLAGS) $(CFLAGS) -MT libgstcairo_la-gstcairo-marshal.lo -MD -MP -MF $(DEPDIR)/libgstcairo_la-gstcairo-marshal.Tpo -c -o libgstcairo_la-gstcairo-marshal.lo `test -f 'gstcairo-marshal.c' || echo '$(srcdir)/'`gstcairo-marshal.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstcairo_la-gstcairo-marshal.Tpo $(DEPDIR)/libgstcairo_la-gstcairo-marshal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstcairo-marshal.c' object='libgstcairo_la-gstcairo-marshal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcairo_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcairo_la_CFLAGS) $(CFLAGS) -c -o libgstcairo_la-gstcairo-marshal.lo `test -f 'gstcairo-marshal.c' || echo '$(srcdir)/'`gstcairo-marshal.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# these are all the rules generating the relevant files
+@USE_CAIRO_GOBJECT_TRUE@$(glib_gen_basename)-marshal.h: $(glib_gen_basename)-marshal.list
+@USE_CAIRO_GOBJECT_TRUE@ $(AM_V_GEN)glib-genmarshal --header --prefix=$(glib_gen_prefix)_marshal $^ > $(glib_gen_basename)-marshal.h.tmp && \
+@USE_CAIRO_GOBJECT_TRUE@ mv $(glib_gen_basename)-marshal.h.tmp $(glib_gen_basename)-marshal.h
+
+@USE_CAIRO_GOBJECT_TRUE@$(glib_gen_basename)-marshal.c: $(glib_gen_basename)-marshal.list
+@USE_CAIRO_GOBJECT_TRUE@ $(AM_V_GEN)echo "#include \"$(glib_gen_basename)-marshal.h\"" >> $(glib_gen_basename)-marshal.c.tmp && \
+@USE_CAIRO_GOBJECT_TRUE@ glib-genmarshal --body --prefix=$(glib_gen_prefix)_marshal $^ >> $(glib_gen_basename)-marshal.c.tmp && \
+@USE_CAIRO_GOBJECT_TRUE@ mv $(glib_gen_basename)-marshal.c.tmp $(glib_gen_basename)-marshal.c
+
+@USE_CAIRO_GOBJECT_TRUE@$(glib_gen_basename)-enumtypes.h: $(glib_enum_headers)
+@USE_CAIRO_GOBJECT_TRUE@ $(AM_V_GEN)glib-mkenums \
+@USE_CAIRO_GOBJECT_TRUE@ --fhead "#ifndef __$(glib_enum_define)_ENUM_TYPES_H__\n#define __$(glib_enum_define)_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
+@USE_CAIRO_GOBJECT_TRUE@ --fprod "\n/* enumerations from \"@filename@\" */\n" \
+@USE_CAIRO_GOBJECT_TRUE@ --vhead "GType @enum_name@_get_type (void);\n#define GST_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \
+@USE_CAIRO_GOBJECT_TRUE@ --ftail "G_END_DECLS\n\n#endif /* __$(glib_enum_define)_ENUM_TYPES_H__ */" \
+@USE_CAIRO_GOBJECT_TRUE@ $^ > $@
+
+@USE_CAIRO_GOBJECT_TRUE@$(glib_gen_basename)-enumtypes.c: $(glib_enum_headers)
+@USE_CAIRO_GOBJECT_TRUE@ @if test "x$(glib_enum_headers)" = "x"; then echo "ERROR: glib_enum_headers is empty, please fix Makefile"; exit 1; fi
+@USE_CAIRO_GOBJECT_TRUE@ $(AM_V_GEN)glib-mkenums \
+@USE_CAIRO_GOBJECT_TRUE@ --fhead "#include \"$(glib_gen_basename)-enumtypes.h\"\n$(enum_headers)" \
+@USE_CAIRO_GOBJECT_TRUE@ --fprod "\n/* enumerations from \"@filename@\" */" \
+@USE_CAIRO_GOBJECT_TRUE@ --vhead "GType\n@enum_name@_get_type (void)\n{\n static volatile gsize g_define_type_id__volatile = 0;\n if (g_once_init_enter (&g_define_type_id__volatile)) {\n static const G@Type@Value values[] = {" \
+@USE_CAIRO_GOBJECT_TRUE@ --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
+@USE_CAIRO_GOBJECT_TRUE@ --vtail " { 0, NULL, NULL }\n };\n GType g_define_type_id = g_@type@_register_static (\"@EnumName@\", values);\n g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);\n }\n return g_define_type_id__volatile;\n}\n" \
+@USE_CAIRO_GOBJECT_TRUE@ $^ > $@
+
+# a hack rule to make sure .Plo files exist because they get include'd
+# from Makefile's
+@USE_CAIRO_GOBJECT_TRUE@.deps/%-marshal.Plo:
+@USE_CAIRO_GOBJECT_TRUE@ @touch $@
+
+@USE_CAIRO_GOBJECT_TRUE@.deps/%-enumtypes.Plo:
+@USE_CAIRO_GOBJECT_TRUE@ @touch $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/cairo/gstcairo-marshal.list b/ext/cairo/gstcairo-marshal.list
new file mode 100644
index 0000000..b637870
--- /dev/null
+++ b/ext/cairo/gstcairo-marshal.list
@@ -0,0 +1,2 @@
+VOID:BOXED,UINT64,UINT64
+VOID:BOXED
diff --git a/ext/cairo/gstcairo.c b/ext/cairo/gstcairo.c
new file mode 100644
index 0000000..5d4c323
--- /dev/null
+++ b/ext/cairo/gstcairo.c
@@ -0,0 +1,59 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003,2004> David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gsttimeoverlay.h>
+#include <gsttextoverlay.h>
+#include <gstcairorender.h>
+
+#ifdef HAVE_CAIRO_GOBJECT
+#include <gstcairooverlay.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+
+GST_DEBUG_CATEGORY (cairo_debug);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ gst_element_register (plugin, "cairotextoverlay", GST_RANK_NONE,
+ GST_TYPE_CAIRO_TEXT_OVERLAY);
+ gst_element_register (plugin, "cairotimeoverlay", GST_RANK_NONE,
+ GST_TYPE_CAIRO_TIME_OVERLAY);
+#ifdef HAVE_CAIRO_GOBJECT
+ gst_element_register (plugin, "cairooverlay", GST_RANK_NONE,
+ GST_TYPE_CAIRO_OVERLAY);
+#endif
+ gst_element_register (plugin, "cairorender", GST_RANK_SECONDARY,
+ GST_TYPE_CAIRO_RENDER);
+
+ GST_DEBUG_CATEGORY_INIT (cairo_debug, "cairo", 0, "Cairo elements");
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "cairo",
+ "Cairo-based elements", plugin_init, VERSION,
+ GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/ext/cairo/gstcairooverlay.c b/ext/cairo/gstcairooverlay.c
new file mode 100644
index 0000000..a19aed6
--- /dev/null
+++ b/ext/cairo/gstcairooverlay.c
@@ -0,0 +1,250 @@
+/* GStreamer
+ * Copyright (C) <2011> Jon Nordby <jononor@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-cairooverlay
+ *
+ * cairooverlay renders an overlay using a application provided render function.
+ *
+ * The full example can be found in tests/examples/cairo/cairo_overlay.c
+ * <refsect2>
+ * <title>Example code</title>
+ * |[
+ *
+ * #include &lt;gst/gst.h&gt;
+ * #include &lt;gst/video/video.h&gt;
+ *
+ * ...
+ *
+ * typedef struct {
+ * gboolean valid;
+ * int width;
+ * int height;
+ * } CairoOverlayState;
+ *
+ * ...
+ *
+ * static void
+ * prepare_overlay (GstElement * overlay, GstCaps * caps, gpointer user_data)
+ * {
+ * CairoOverlayState *state = (CairoOverlayState *)user_data;
+ *
+ * gst_video_format_parse_caps (caps, NULL, &amp;state-&gt;width, &amp;state-&gt;height);
+ * state-&gt;valid = TRUE;
+ * }
+ *
+ * static void
+ * draw_overlay (GstElement * overlay, cairo_t * cr, guint64 timestamp,
+ * guint64 duration, gpointer user_data)
+ * {
+ * CairoOverlayState *s = (CairoOverlayState *)user_data;
+ * double scale;
+ *
+ * if (!s-&gt;valid)
+ * return;
+ *
+ * scale = 2*(((timestamp/(int)1e7) % 70)+30)/100.0;
+ * cairo_translate(cr, s-&gt;width/2, (s-&gt;height/2)-30);
+ * cairo_scale (cr, scale, scale);
+ *
+ * cairo_move_to (cr, 0, 0);
+ * cairo_curve_to (cr, 0,-30, -50,-30, -50,0);
+ * cairo_curve_to (cr, -50,30, 0,35, 0,60 );
+ * cairo_curve_to (cr, 0,35, 50,30, 50,0 ); *
+ * cairo_curve_to (cr, 50,-30, 0,-30, 0,0 );
+ * cairo_set_source_rgba (cr, 0.9, 0.0, 0.1, 0.7);
+ * cairo_fill (cr);
+ * }
+ *
+ * ...
+ *
+ * cairo_overlay = gst_element_factory_make (&quot;cairooverlay&quot;, &quot;overlay&quot;);
+ *
+ * g_signal_connect (cairo_overlay, &quot;draw&quot;, G_CALLBACK (draw_overlay),
+ * overlay_state);
+ * g_signal_connect (cairo_overlay, &quot;caps-changed&quot;,
+ * G_CALLBACK (prepare_overlay), overlay_state);
+ * ...
+ *
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstcairooverlay.h"
+#include "gstcairo-marshal.h"
+
+#include <gst/video/video.h>
+
+#include <cairo.h>
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define TEMPLATE_CAPS GST_VIDEO_CAPS_BGRx " ; " GST_VIDEO_CAPS_BGRA " ; "
+#else
+#define TEMPLATE_CAPS GST_VIDEO_CAPS_xRGB " ; " GST_VIDEO_CAPS_ARGB " ; "
+
+#endif
+
+static GstStaticPadTemplate gst_cairo_overlay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (TEMPLATE_CAPS)
+ );
+
+static GstStaticPadTemplate gst_cairo_overlay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (TEMPLATE_CAPS)
+ );
+
+
+GST_BOILERPLATE (GstCairoOverlay, gst_cairo_overlay, GstVideoFilter,
+ GST_TYPE_VIDEO_FILTER);
+
+enum
+{
+ SIGNAL_DRAW,
+ SIGNAL_CAPS_CHANGED,
+ N_SIGNALS
+};
+
+static guint gst_cairo_overlay_signals[N_SIGNALS];
+
+static gboolean
+gst_cairo_overlay_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
+ GstCaps * outcaps)
+{
+ GstCairoOverlay *overlay = GST_CAIRO_OVERLAY (btrans);
+ gboolean ret;
+
+ ret =
+ gst_video_format_parse_caps (incaps, &overlay->format, &overlay->width,
+ &overlay->height);
+ if (G_UNLIKELY (!ret))
+ return FALSE;
+
+ g_signal_emit (overlay, gst_cairo_overlay_signals[SIGNAL_CAPS_CHANGED], 0,
+ incaps, NULL);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_cairo_overlay_transform_ip (GstBaseTransform * btrans, GstBuffer * buf)
+{
+
+ GstCairoOverlay *overlay = GST_CAIRO_OVERLAY (btrans);
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ cairo_format_t format;
+
+ format = (overlay->format == GST_VIDEO_FORMAT_ARGB
+ || overlay->format == GST_VIDEO_FORMAT_BGRA) ?
+ CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24;
+
+ surface =
+ cairo_image_surface_create_for_data (GST_BUFFER_DATA (buf), format,
+ overlay->width, overlay->height, overlay->width * 4);
+ if (G_UNLIKELY (!surface))
+ return GST_FLOW_ERROR;
+
+ cr = cairo_create (surface);
+ if (G_UNLIKELY (!cr)) {
+ cairo_surface_destroy (surface);
+ return GST_FLOW_ERROR;
+ }
+
+ g_signal_emit (overlay, gst_cairo_overlay_signals[SIGNAL_DRAW], 0,
+ cr, GST_BUFFER_TIMESTAMP (buf), GST_BUFFER_DURATION (buf), NULL);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ return GST_FLOW_OK;
+}
+
+static void
+gst_cairo_overlay_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details_simple (element_class, "Cairo overlay",
+ "Filter/Editor/Video",
+ "Render overlay on a video stream using Cairo",
+ "Jon Nordby <jononor@gmail.com>");
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_cairo_overlay_sink_template);
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_cairo_overlay_src_template);
+}
+
+static void
+gst_cairo_overlay_class_init (GstCairoOverlayClass * klass)
+{
+ GstBaseTransformClass *trans_class;
+
+ trans_class = (GstBaseTransformClass *) klass;
+
+ trans_class->set_caps = gst_cairo_overlay_set_caps;
+ trans_class->transform_ip = gst_cairo_overlay_transform_ip;
+
+ /**
+ * GstCairoOverlay::draw:
+ * @overlay: Overlay element emitting the signal.
+ * @cr: Cairo context to draw to.
+ * @timestamp: Timestamp (see #GstClockTime) of the current buffer.
+ * @duration: Duration (see #GstClockTime) of the current buffer.
+ *
+ * This signal is emitted when the overlay should be drawn.
+ */
+ gst_cairo_overlay_signals[SIGNAL_DRAW] =
+ g_signal_new ("draw",
+ G_TYPE_FROM_CLASS (klass),
+ 0,
+ 0,
+ NULL,
+ NULL,
+ gst_cairo_marshal_VOID__BOXED_UINT64_UINT64,
+ G_TYPE_NONE, 3, CAIRO_GOBJECT_TYPE_CONTEXT, G_TYPE_UINT64, G_TYPE_UINT64);
+
+ /**
+ * GstCairoOverlay::caps-changed:
+ * @overlay: Overlay element emitting the signal.
+ * @caps: The #GstCaps of the element.
+ *
+ * This signal is emitted when the caps of the element has changed.
+ */
+ gst_cairo_overlay_signals[SIGNAL_CAPS_CHANGED] =
+ g_signal_new ("caps-changed",
+ G_TYPE_FROM_CLASS (klass),
+ 0,
+ 0,
+ NULL, NULL, gst_cairo_marshal_VOID__BOXED, G_TYPE_NONE, 1, GST_TYPE_CAPS);
+}
+
+static void
+gst_cairo_overlay_init (GstCairoOverlay * overlay, GstCairoOverlayClass * klass)
+{
+}
diff --git a/ext/cairo/gstcairooverlay.h b/ext/cairo/gstcairooverlay.h
new file mode 100644
index 0000000..0c1ad27
--- /dev/null
+++ b/ext/cairo/gstcairooverlay.h
@@ -0,0 +1,63 @@
+/* GStreamer
+ * Copyright (C) <2011> Jon Nordby <jononor@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CAIRO_OVERLAY_H__
+#define __GST_CAIRO_OVERLAY_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+
+#include <cairo.h>
+#include <cairo-gobject.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CAIRO_OVERLAY \
+ (gst_cairo_overlay_get_type())
+#define GST_CAIRO_OVERLAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAIRO_OVERLAY,GstCairoOverlay))
+#define GST_CAIRO_OVERLAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAIRO_OVERLAY,GstCairoOverlayClass))
+#define GST_IS_CAIRO_OVERLAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAIRO_OVERLAY))
+#define GST_IS_CAIRO_OVERLAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAIRO_OVERLAY))
+
+typedef struct _GstCairoOverlay GstCairoOverlay;
+typedef struct _GstCairoOverlayClass GstCairoOverlayClass;
+
+struct _GstCairoOverlay {
+ GstVideoFilter parent_instance;
+
+ /* < private > */
+ GstVideoFormat format;
+ gint width;
+ gint height;
+};
+
+struct _GstCairoOverlayClass {
+ GstVideoFilterClass parent_class;
+};
+
+GType gst_cairo_overlay_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_CAIRO_OVERLAY_H__ */
diff --git a/ext/cairo/gstcairorender.c b/ext/cairo/gstcairorender.c
new file mode 100644
index 0000000..870ac17
--- /dev/null
+++ b/ext/cairo/gstcairorender.c
@@ -0,0 +1,383 @@
+/* GStreamer
+ *
+ * Copyright (C) 2006-2009 Lutz Mueller <lutz@topfrose.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-cairorender
+ *
+ * cairorender encodes a video stream into PDF, SVG, PNG or Postscript
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch videotestsrc num-buffers=3 ! cairorender ! "application/pdf" ! filesink location=test.pdf
+ * ]|
+ * </refsect2>
+ */
+
+#include "gstcairorender.h"
+
+#include <cairo.h>
+#include <cairo-features.h>
+#ifdef CAIRO_HAS_PS_SURFACE
+#include <cairo-ps.h>
+#endif
+#ifdef CAIRO_HAS_PDF_SURFACE
+#include <cairo-pdf.h>
+#endif
+#ifdef CAIRO_HAS_SVG_SURFACE
+#include <cairo-svg.h>
+#endif
+
+#include <gst/video/video.h>
+
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (cairo_render_debug);
+#define GST_CAT_DEFAULT cairo_render_debug
+
+static gboolean
+gst_cairo_render_event (GstPad * pad, GstEvent * e)
+{
+ GstCairoRender *c = GST_CAIRO_RENDER (GST_PAD_PARENT (pad));
+
+ switch (GST_EVENT_TYPE (e)) {
+ case GST_EVENT_EOS:
+ if (c->surface)
+ cairo_surface_finish (c->surface);
+ break;
+ default:
+ break;
+ }
+ return gst_pad_event_default (pad, e);
+}
+
+static cairo_status_t
+write_func (void *closure, const unsigned char *data, unsigned int length)
+{
+ GstCairoRender *c = GST_CAIRO_RENDER (closure);
+ GstBuffer *buf;
+ GstFlowReturn r;
+
+ buf = gst_buffer_new ();
+ gst_buffer_set_data (buf, (guint8 *) data, length);
+ gst_buffer_set_caps (buf, GST_PAD_CAPS (c->src));
+ if ((r = gst_pad_push (c->src, buf)) != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (c, "Could not pass on buffer: %s.",
+ gst_flow_get_name (r));
+ return CAIRO_STATUS_WRITE_ERROR;
+ }
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+read_buffer (void *closure, unsigned char *data, unsigned int length)
+{
+ GstBuffer *buf = GST_BUFFER (closure);
+
+ if (GST_BUFFER_OFFSET (buf) + length > GST_BUFFER_SIZE (buf))
+ return CAIRO_STATUS_READ_ERROR;
+ memcpy (data, GST_BUFFER_DATA (buf) + GST_BUFFER_OFFSET (buf), length);
+ GST_BUFFER_OFFSET (buf) += length;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static gboolean
+gst_cairo_render_push_surface (GstCairoRender * c, cairo_surface_t * surface)
+{
+ cairo_status_t s = 0;
+ cairo_t *cr;
+
+ if (!c->surface) {
+ s = cairo_surface_write_to_png_stream (surface, write_func, c);
+ cairo_surface_destroy (surface);
+ if (s != CAIRO_STATUS_SUCCESS) {
+ GST_DEBUG_OBJECT (c, "Could not create PNG stream: %s.",
+ cairo_status_to_string (s));
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ cr = cairo_create (c->surface);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+ cairo_show_page (cr);
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+ return (TRUE);
+}
+
+static GstFlowReturn
+gst_cairo_render_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstCairoRender *c = GST_CAIRO_RENDER (GST_PAD_PARENT (pad));
+ cairo_surface_t *s;
+ gboolean success;
+
+ if (G_UNLIKELY (c->width <= 0 || c->height <= 0 || c->stride <= 0))
+ return GST_FLOW_NOT_NEGOTIATED;
+
+ if (c->png) {
+ GST_BUFFER_OFFSET (buf) = 0;
+ s = cairo_image_surface_create_from_png_stream (read_buffer, buf);
+ } else {
+ if (c->format == CAIRO_FORMAT_ARGB32) {
+ guint i, j;
+ guint8 *data = GST_BUFFER_DATA (buf);
+
+ buf = gst_buffer_make_writable (buf);
+
+ /* Cairo ARGB is pre-multiplied with the alpha
+ * value, i.e. 0x80008000 is half transparent
+ * green
+ */
+ for (i = 0; i < c->height; i++) {
+ for (j = 0; j < c->width; j++) {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ guint8 alpha = data[3];
+
+ data[0] = (data[0] * alpha) >> 8;
+ data[1] = (data[1] * alpha) >> 8;
+ data[2] = (data[2] * alpha) >> 8;
+#else
+ guint8 alpha = data[0];
+
+ data[1] = (data[1] * alpha) >> 8;
+ data[2] = (data[2] * alpha) >> 8;
+ data[3] = (data[3] * alpha) >> 8;
+#endif
+ data += 4;
+ }
+ }
+ }
+
+ s = cairo_image_surface_create_for_data (GST_BUFFER_DATA (buf),
+ c->format, c->width, c->height, c->stride);
+ }
+
+ success = gst_cairo_render_push_surface (c, s);
+ gst_buffer_unref (buf);
+ return success ? GST_FLOW_OK : GST_FLOW_ERROR;
+}
+
+static gboolean
+gst_cairo_render_setcaps_sink (GstPad * pad, GstCaps * caps)
+{
+ GstCairoRender *c = GST_CAIRO_RENDER (GST_PAD_PARENT (pad));
+ GstStructure *s = gst_caps_get_structure (caps, 0);
+ const gchar *mime = gst_structure_get_name (s);
+ gint fps_n = 0, fps_d = 1;
+ gint w, h;
+
+ GST_DEBUG_OBJECT (c, "Got caps (%s).", mime);
+ if ((c->png = !strcmp (mime, "image/png")))
+ return TRUE;
+
+ /* Width and height */
+ if (!gst_structure_get_int (s, "width", &c->width) ||
+ !gst_structure_get_int (s, "height", &c->height)) {
+ GST_ERROR_OBJECT (c, "Invalid caps");
+ return FALSE;
+ }
+
+ /* Colorspace */
+ if (!strcmp (mime, "video/x-raw-yuv") || !strcmp (mime, "video/x-raw-grey")) {
+ c->format = CAIRO_FORMAT_A8;
+ c->stride = GST_ROUND_UP_4 (c->width);
+ } else if (!strcmp (mime, "video/x-raw-rgb")) {
+ gint bpp;
+
+ if (!gst_structure_get_int (s, "bpp", &bpp)) {
+ GST_ERROR_OBJECT (c, "Invalid caps");
+ return FALSE;
+ }
+
+ c->format = (bpp == 32) ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24;
+ c->stride = 4 * c->width;
+ } else {
+ GST_DEBUG_OBJECT (c, "Unknown mime type '%s'.", mime);
+ return FALSE;
+ }
+
+ /* Framerate */
+ gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d);
+
+ /* Create output caps */
+ caps = gst_pad_get_allowed_caps (c->src);
+ caps = gst_caps_make_writable (caps);
+ gst_caps_truncate (caps);
+ s = gst_caps_get_structure (caps, 0);
+ mime = gst_structure_get_name (s);
+ gst_structure_set (s, "height", G_TYPE_INT, c->height, "width", G_TYPE_INT,
+ c->width, "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
+
+ if (c->surface) {
+ cairo_surface_destroy (c->surface);
+ c->surface = NULL;
+ }
+
+ w = c->width;
+ h = c->height;
+
+ GST_DEBUG_OBJECT (c, "Setting src caps %" GST_PTR_FORMAT, caps);
+ gst_pad_set_caps (c->src, caps);
+
+#if CAIRO_HAS_PS_SURFACE
+ if (!strcmp (mime, "application/postscript")) {
+ c->surface = cairo_ps_surface_create_for_stream (write_func, c, w, h);
+ } else
+#endif
+#if CAIRO_HAS_PDF_SURFACE
+ if (!strcmp (mime, "application/pdf")) {
+ c->surface = cairo_pdf_surface_create_for_stream (write_func, c, w, h);
+ } else
+#endif
+#if CAIRO_HAS_SVG_SURFACE
+ if (!strcmp (mime, "image/svg+xml")) {
+ c->surface = cairo_svg_surface_create_for_stream (write_func, c, w, h);
+ } else
+#endif
+ {
+ gst_caps_unref (caps);
+ return FALSE;
+ }
+
+ gst_caps_unref (caps);
+
+ return TRUE;
+}
+
+
+#define SIZE_CAPS "width = (int) [ 1, MAX], height = (int) [ 1, MAX] "
+#if CAIRO_HAS_PDF_SURFACE
+#define PDF_CAPS "application/pdf, " SIZE_CAPS
+#else
+#define PDF_CAPS
+#endif
+#if CAIRO_HAS_PDF_SURFACE && (CAIRO_HAS_PS_SURFACE || CAIRO_HAS_SVG_SURFACE || CAIRO_HAS_PNG_FUNCTIONS)
+#define JOIN1 ";"
+#else
+#define JOIN1
+#endif
+#if CAIRO_HAS_PS_SURFACE
+#define PS_CAPS "application/postscript, " SIZE_CAPS
+#else
+#define PS_CAPS
+#endif
+#if (CAIRO_HAS_PDF_SURFACE || CAIRO_HAS_PS_SURFACE) && (CAIRO_HAS_SVG_SURFACE || CAIRO_HAS_PNG_FUNCTIONS)
+#define JOIN2 ";"
+#else
+#define JOIN2
+#endif
+#if CAIRO_HAS_SVG_SURFACE
+#define SVG_CAPS "image/svg+xml, " SIZE_CAPS
+#else
+#define SVG_CAPS
+#endif
+#if (CAIRO_HAS_PDF_SURFACE || CAIRO_HAS_PS_SURFACE || CAIRO_HAS_SVG_SURFACE) && CAIRO_HAS_PNG_FUNCTIONS
+#define JOIN3 ";"
+#else
+#define JOIN3
+#endif
+#if CAIRO_HAS_PNG_FUNCTIONS
+#define PNG_CAPS "image/png, " SIZE_CAPS
+#define PNG_CAPS2 "; image/png, " SIZE_CAPS
+#else
+#define PNG_CAPS
+#define PNG_CAPS2
+#endif
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define ARGB_CAPS GST_VIDEO_CAPS_BGRx " ; " GST_VIDEO_CAPS_BGRA " ; "
+#else
+#define ARGB_CAPS GST_VIDEO_CAPS_xRGB " ; " GST_VIDEO_CAPS_ARGB " ; "
+#endif
+static GstStaticPadTemplate t_src = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (PDF_CAPS JOIN1 PS_CAPS JOIN2 SVG_CAPS JOIN3 PNG_CAPS));
+static GstStaticPadTemplate t_snk = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS (ARGB_CAPS
+ GST_VIDEO_CAPS_YUV ("Y800") " ; "
+ "video/x-raw-gray, "
+ "bpp = 8, "
+ "depth = 8, "
+ "width = " GST_VIDEO_SIZE_RANGE ", "
+ "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = " GST_VIDEO_FPS_RANGE
+ PNG_CAPS2));
+
+GST_BOILERPLATE (GstCairoRender, gst_cairo_render, GstElement,
+ GST_TYPE_ELEMENT);
+
+static void
+gst_cairo_render_init (GstCairoRender * c, GstCairoRenderClass * klass)
+{
+ /* The sink */
+ c->snk = gst_pad_new_from_static_template (&t_snk, "sink");
+ gst_pad_set_event_function (c->snk, gst_cairo_render_event);
+ gst_pad_set_chain_function (c->snk, gst_cairo_render_chain);
+ gst_pad_set_setcaps_function (c->snk, gst_cairo_render_setcaps_sink);
+ gst_pad_use_fixed_caps (c->snk);
+ gst_element_add_pad (GST_ELEMENT (c), c->snk);
+
+ /* The source */
+ c->src = gst_pad_new_from_static_template (&t_src, "src");
+ gst_pad_use_fixed_caps (c->src);
+ gst_element_add_pad (GST_ELEMENT (c), c->src);
+
+ c->width = 0;
+ c->height = 0;
+ c->stride = 0;
+}
+
+static void
+gst_cairo_render_base_init (gpointer g_class)
+{
+ GstElementClass *ec = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details_simple (ec, "Cairo encoder",
+ "Codec/Encoder", "Encodes streams using Cairo",
+ "Lutz Mueller <lutz@topfrose.de>");
+ gst_element_class_add_static_pad_template (ec, &t_snk);
+ gst_element_class_add_static_pad_template (ec, &t_src);
+}
+
+static void
+gst_cairo_render_finalize (GObject * object)
+{
+ GstCairoRender *c = GST_CAIRO_RENDER (object);
+
+ if (c->surface) {
+ cairo_surface_destroy (c->surface);
+ c->surface = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_cairo_render_class_init (GstCairoRenderClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = gst_cairo_render_finalize;
+
+ GST_DEBUG_CATEGORY_INIT (cairo_render_debug, "cairo_render", 0,
+ "Cairo encoder");
+}
diff --git a/ext/cairo/gstcairorender.h b/ext/cairo/gstcairorender.h
new file mode 100644
index 0000000..3f1000e
--- /dev/null
+++ b/ext/cairo/gstcairorender.h
@@ -0,0 +1,63 @@
+/* cairorender: CAIRO plugin for GStreamer
+ *
+ * Copyright (C) 2006-2009 Lutz Mueller <lutz@topfrose.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CAIRO_RENDER_H_
+#define __GST_CAIRO_RENDER_H__
+
+#include <gst/gst.h>
+#include <cairo.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CAIRO_RENDER (gst_cairo_render_get_type())
+#define GST_CAIRO_RENDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAIRO_RENDER,GstCairoRender))
+#define GST_CAIRO_RENDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAIRO_RENDER,GstCairoRenderClass))
+
+typedef struct _GstCairoRender GstCairoRender;
+typedef struct _GstCairoRenderClass GstCairoRenderClass;
+
+struct _GstCairoRender
+{
+ GstElement parent;
+
+ GstPad *snk, *src;
+
+ /* < private > */
+
+ /* Source */
+ cairo_surface_t *surface;
+ gint width, height, stride;
+
+ /* Sink */
+ gint64 offset, duration;
+ gboolean png;
+ cairo_format_t format;
+};
+
+struct _GstCairoRenderClass
+{
+ GstElementClass parent_class;
+};
+
+GType gst_cairo_render_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GST_CAIRO_RENDER_H__ */
diff --git a/ext/cairo/gsttextoverlay.c b/ext/cairo/gsttextoverlay.c
new file mode 100644
index 0000000..8cb39cc
--- /dev/null
+++ b/ext/cairo/gsttextoverlay.c
@@ -0,0 +1,1042 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:element-cairotextoverlay
+ *
+ * cairotextoverlay renders the text on top of the video frames.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch videotestsrc ! cairotextoverlay text="hello" ! autovideosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <string.h>
+#include <gst/video/video.h>
+#include "gsttextoverlay.h"
+
+#include <cairo.h>
+
+/* FIXME:
+ * - calculating the position of the shading rectangle is
+ * not really right (try with text "L"), to say the least.
+ * Seems to work at least with latin script though.
+ * - check final x/y position and text width/height so that
+ * we don't do out-of-memory access when blitting the text.
+ * Also, we do not want to blit over the right or left margin.
+ * - what about text with newline characters? Cairo doesn't deal
+ * with that (we'd need to fix text_height usage for that as well)
+ * - upstream caps renegotiation, ie. when video window gets resized
+ */
+
+GST_DEBUG_CATEGORY_EXTERN (cairo_debug);
+#define GST_CAT_DEFAULT cairo_debug
+
+enum
+{
+ ARG_0,
+ ARG_TEXT,
+ ARG_SHADING,
+ ARG_VALIGN,
+ ARG_HALIGN,
+ ARG_XPAD,
+ ARG_YPAD,
+ ARG_DELTAX,
+ ARG_DELTAY,
+ ARG_SILENT,
+ ARG_FONT_DESC
+};
+
+#define DEFAULT_YPAD 25
+#define DEFAULT_XPAD 25
+#define DEFAULT_FONT "sans"
+#define DEFAULT_SILENT FALSE
+
+#define GST_CAIRO_TEXT_OVERLAY_DEFAULT_SCALE 20.0
+
+static GstStaticPadTemplate cairo_text_overlay_src_template_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
+ );
+
+static GstStaticPadTemplate video_sink_template_factory =
+GST_STATIC_PAD_TEMPLATE ("video_sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
+ );
+
+static GstStaticPadTemplate text_sink_template_factory =
+GST_STATIC_PAD_TEMPLATE ("text_sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("text/plain")
+ );
+
+static void gst_text_overlay_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static GstStateChangeReturn gst_text_overlay_change_state (GstElement * element,
+ GstStateChange transition);
+static GstCaps *gst_text_overlay_getcaps (GstPad * pad);
+static gboolean gst_text_overlay_setcaps (GstPad * pad, GstCaps * caps);
+static GstPadLinkReturn gst_text_overlay_text_pad_linked (GstPad * pad,
+ GstPad * peer);
+static void gst_text_overlay_text_pad_unlinked (GstPad * pad);
+static GstFlowReturn gst_text_overlay_collected (GstCollectPads * pads,
+ gpointer data);
+static void gst_text_overlay_finalize (GObject * object);
+static void gst_text_overlay_font_init (GstCairoTextOverlay * overlay);
+static gboolean gst_text_overlay_src_event (GstPad * pad, GstEvent * event);
+static gboolean gst_text_overlay_video_event (GstPad * pad, GstEvent * event);
+
+/* These macros are adapted from videotestsrc.c */
+#define I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
+#define I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
+#define I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2)
+
+#define I420_Y_OFFSET(w,h) (0)
+#define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
+#define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
+
+#define I420_SIZE(w,h) (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
+
+GST_BOILERPLATE (GstCairoTextOverlay, gst_text_overlay, GstElement,
+ GST_TYPE_ELEMENT);
+
+static void
+gst_text_overlay_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &cairo_text_overlay_src_template_factory);
+ gst_element_class_add_static_pad_template (element_class,
+ &video_sink_template_factory);
+ gst_element_class_add_static_pad_template (element_class,
+ &text_sink_template_factory);
+
+ gst_element_class_set_details_simple (element_class, "Text overlay",
+ "Filter/Editor/Video",
+ "Adds text strings on top of a video buffer",
+ "David Schleef <ds@schleef.org>");
+}
+
+static void
+gst_text_overlay_class_init (GstCairoTextOverlayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = gst_text_overlay_finalize;
+ gobject_class->set_property = gst_text_overlay_set_property;
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_text_overlay_change_state);
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TEXT,
+ g_param_spec_string ("text", "text",
+ "Text to be display.", "",
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SHADING,
+ g_param_spec_boolean ("shaded-background", "shaded background",
+ "Whether to shade the background under the text area", FALSE,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VALIGN,
+ g_param_spec_string ("valign", "vertical alignment",
+ "Vertical alignment of the text. "
+ "Can be either 'baseline', 'bottom', or 'top'",
+ "baseline", G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HALIGN,
+ g_param_spec_string ("halign", "horizontal alignment",
+ "Horizontal alignment of the text. "
+ "Can be either 'left', 'right', or 'center'",
+ "center", G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_XPAD,
+ g_param_spec_int ("xpad", "horizontal paddding",
+ "Horizontal paddding when using left/right alignment",
+ G_MININT, G_MAXINT, DEFAULT_XPAD,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_YPAD,
+ g_param_spec_int ("ypad", "vertical padding",
+ "Vertical padding when using top/bottom alignment",
+ G_MININT, G_MAXINT, DEFAULT_YPAD,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DELTAX,
+ g_param_spec_int ("deltax", "X position modifier",
+ "Shift X position to the left or to the right. Unit is pixels.",
+ G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DELTAY,
+ g_param_spec_int ("deltay", "Y position modifier",
+ "Shift Y position up or down. Unit is pixels.",
+ G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FONT_DESC,
+ g_param_spec_string ("font-desc", "font description",
+ "Pango font description of font "
+ "to be used for rendering. "
+ "See documentation of "
+ "pango_font_description_from_string"
+ " for syntax.", "", G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ /* FIXME 0.11: rename to "visible" or "text-visible" or "render-text" */
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
+ g_param_spec_boolean ("silent", "silent",
+ "Whether to render the text string",
+ DEFAULT_SILENT, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_text_overlay_finalize (GObject * object)
+{
+ GstCairoTextOverlay *overlay = GST_CAIRO_TEXT_OVERLAY (object);
+
+ gst_collect_pads_stop (overlay->collect);
+ gst_object_unref (overlay->collect);
+
+ g_free (overlay->text_fill_image);
+ g_free (overlay->text_outline_image);
+
+ g_free (overlay->default_text);
+ g_free (overlay->font);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_text_overlay_init (GstCairoTextOverlay * overlay,
+ GstCairoTextOverlayClass * klass)
+{
+ /* video sink */
+ overlay->video_sinkpad =
+ gst_pad_new_from_static_template (&video_sink_template_factory,
+ "video_sink");
+ gst_pad_set_getcaps_function (overlay->video_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_text_overlay_getcaps));
+ gst_pad_set_setcaps_function (overlay->video_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_text_overlay_setcaps));
+ gst_element_add_pad (GST_ELEMENT (overlay), overlay->video_sinkpad);
+
+ /* text sink */
+ overlay->text_sinkpad =
+ gst_pad_new_from_static_template (&text_sink_template_factory,
+ "text_sink");
+ gst_pad_set_link_function (overlay->text_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_text_overlay_text_pad_linked));
+ gst_pad_set_unlink_function (overlay->text_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_text_overlay_text_pad_unlinked));
+ gst_element_add_pad (GST_ELEMENT (overlay), overlay->text_sinkpad);
+
+ /* (video) source */
+ overlay->srcpad =
+ gst_pad_new_from_static_template
+ (&cairo_text_overlay_src_template_factory, "src");
+ gst_pad_set_getcaps_function (overlay->srcpad,
+ GST_DEBUG_FUNCPTR (gst_text_overlay_getcaps));
+ gst_pad_set_event_function (overlay->srcpad,
+ GST_DEBUG_FUNCPTR (gst_text_overlay_src_event));
+ gst_element_add_pad (GST_ELEMENT (overlay), overlay->srcpad);
+
+ overlay->halign = GST_CAIRO_TEXT_OVERLAY_HALIGN_CENTER;
+ overlay->valign = GST_CAIRO_TEXT_OVERLAY_VALIGN_BASELINE;
+ overlay->xpad = DEFAULT_XPAD;
+ overlay->ypad = DEFAULT_YPAD;
+ overlay->deltax = 0;
+ overlay->deltay = 0;
+
+ overlay->default_text = g_strdup ("");
+ overlay->need_render = TRUE;
+
+ overlay->font = g_strdup (DEFAULT_FONT);
+ gst_text_overlay_font_init (overlay);
+
+ overlay->silent = DEFAULT_SILENT;
+
+ overlay->fps_n = 0;
+ overlay->fps_d = 1;
+
+ overlay->collect = gst_collect_pads_new ();
+
+ gst_collect_pads_set_function (overlay->collect,
+ GST_DEBUG_FUNCPTR (gst_text_overlay_collected), overlay);
+
+ overlay->video_collect_data = gst_collect_pads_add_pad (overlay->collect,
+ overlay->video_sinkpad, sizeof (GstCollectData));
+
+ /* FIXME: hacked way to override/extend the event function of
+ * GstCollectPads; because it sets its own event function giving the
+ * element no access to events. Nicked from avimux. */
+ overlay->collect_event =
+ (GstPadEventFunction) GST_PAD_EVENTFUNC (overlay->video_sinkpad);
+ gst_pad_set_event_function (overlay->video_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_text_overlay_video_event));
+
+ /* text pad will be added when it is linked */
+ overlay->text_collect_data = NULL;
+}
+
+static void
+gst_text_overlay_font_init (GstCairoTextOverlay * overlay)
+{
+ cairo_font_extents_t font_extents;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ gchar *font_desc, *sep;
+
+ font_desc = g_ascii_strdown (overlay->font, -1);
+
+ /* cairo_select_font_face() does not parse the size at the end, so we have
+ * to do that ourselves; same for slate and weight */
+ sep = MAX (strrchr (font_desc, ' '), strrchr (font_desc, ','));
+ if (sep != NULL && g_strtod (sep, NULL) > 0.0) {
+ /* there may be a suffix such as 'px', but we just ignore that for now */
+ overlay->scale = g_strtod (sep, NULL);
+ } else {
+ overlay->scale = GST_CAIRO_TEXT_OVERLAY_DEFAULT_SCALE;
+ }
+ if (strstr (font_desc, "bold"))
+ overlay->weight = CAIRO_FONT_WEIGHT_BOLD;
+ else
+ overlay->weight = CAIRO_FONT_WEIGHT_NORMAL;
+
+ if (strstr (font_desc, "italic"))
+ overlay->slant = CAIRO_FONT_SLANT_ITALIC;
+ else if (strstr (font_desc, "oblique"))
+ overlay->slant = CAIRO_FONT_SLANT_OBLIQUE;
+ else
+ overlay->slant = CAIRO_FONT_SLANT_NORMAL;
+
+ GST_LOG_OBJECT (overlay, "Font desc: '%s', scale=%f, weight=%d, slant=%d",
+ overlay->font, overlay->scale, overlay->weight, overlay->slant);
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 256, 256);
+ cr = cairo_create (surface);
+
+ cairo_select_font_face (cr, overlay->font, overlay->slant, overlay->weight);
+ cairo_set_font_size (cr, overlay->scale);
+
+ /* this has a static leak:
+ * http://lists.freedesktop.org/archives/cairo/2007-May/010623.html
+ */
+ cairo_font_extents (cr, &font_extents);
+ overlay->font_height = GST_ROUND_UP_2 ((guint) font_extents.height);
+ overlay->need_render = TRUE;
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+ g_free (font_desc);
+}
+
+static void
+gst_text_overlay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstCairoTextOverlay *overlay = GST_CAIRO_TEXT_OVERLAY (object);
+
+ GST_OBJECT_LOCK (overlay);
+
+ switch (prop_id) {
+ case ARG_TEXT:{
+ g_free (overlay->default_text);
+ overlay->default_text = g_value_dup_string (value);
+ break;
+ }
+ case ARG_SHADING:{
+ overlay->want_shading = g_value_get_boolean (value);
+ break;
+ }
+ case ARG_VALIGN:{
+ const gchar *s = g_value_get_string (value);
+
+ if (g_ascii_strcasecmp (s, "baseline") == 0)
+ overlay->valign = GST_CAIRO_TEXT_OVERLAY_VALIGN_BASELINE;
+ else if (g_ascii_strcasecmp (s, "bottom") == 0)
+ overlay->valign = GST_CAIRO_TEXT_OVERLAY_VALIGN_BOTTOM;
+ else if (g_ascii_strcasecmp (s, "top") == 0)
+ overlay->valign = GST_CAIRO_TEXT_OVERLAY_VALIGN_TOP;
+ else
+ g_warning ("Invalid 'valign' property value: %s", s);
+ break;
+ }
+ case ARG_HALIGN:{
+ const gchar *s = g_value_get_string (value);
+
+ if (g_ascii_strcasecmp (s, "left") == 0)
+ overlay->halign = GST_CAIRO_TEXT_OVERLAY_HALIGN_LEFT;
+ else if (g_ascii_strcasecmp (s, "right") == 0)
+ overlay->halign = GST_CAIRO_TEXT_OVERLAY_HALIGN_RIGHT;
+ else if (g_ascii_strcasecmp (s, "center") == 0)
+ overlay->halign = GST_CAIRO_TEXT_OVERLAY_HALIGN_CENTER;
+ else
+ g_warning ("Invalid 'halign' property value: %s", s);
+ break;
+ }
+ case ARG_XPAD:{
+ overlay->xpad = g_value_get_int (value);
+ break;
+ }
+ case ARG_YPAD:{
+ overlay->ypad = g_value_get_int (value);
+ break;
+ }
+ case ARG_DELTAX:{
+ overlay->deltax = g_value_get_int (value);
+ break;
+ }
+ case ARG_DELTAY:{
+ overlay->deltay = g_value_get_int (value);
+ break;
+ }
+ case ARG_FONT_DESC:{
+ g_free (overlay->font);
+ overlay->font = g_value_dup_string (value);
+ if (overlay->font == NULL)
+ overlay->font = g_strdup (DEFAULT_FONT);
+ gst_text_overlay_font_init (overlay);
+ break;
+ }
+ case ARG_SILENT:
+ overlay->silent = g_value_get_boolean (value);
+ break;
+ default:{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ }
+
+ overlay->need_render = TRUE;
+
+ GST_OBJECT_UNLOCK (overlay);
+}
+
+static void
+gst_text_overlay_render_text (GstCairoTextOverlay * overlay,
+ const gchar * text, gint textlen)
+{
+ cairo_text_extents_t extents;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ gchar *string;
+ double x, y;
+
+ if (overlay->silent) {
+ GST_DEBUG_OBJECT (overlay, "Silent mode, not rendering");
+ return;
+ }
+
+ if (textlen < 0)
+ textlen = strlen (text);
+
+ if (!overlay->need_render) {
+ GST_DEBUG ("Using previously rendered text.");
+ g_return_if_fail (overlay->text_fill_image != NULL);
+ g_return_if_fail (overlay->text_outline_image != NULL);
+ return;
+ }
+
+ string = g_strndup (text, textlen);
+ GST_DEBUG ("Rendering text '%s' on cairo RGBA surface", string);
+
+ overlay->text_fill_image =
+ g_realloc (overlay->text_fill_image,
+ 4 * overlay->width * overlay->font_height);
+
+ surface = cairo_image_surface_create_for_data (overlay->text_fill_image,
+ CAIRO_FORMAT_ARGB32, overlay->width, overlay->font_height,
+ overlay->width * 4);
+
+ cr = cairo_create (surface);
+
+ cairo_select_font_face (cr, overlay->font, overlay->slant, overlay->weight);
+ cairo_set_font_size (cr, overlay->scale);
+
+ cairo_save (cr);
+ cairo_rectangle (cr, 0, 0, overlay->width, overlay->font_height);
+ cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_fill (cr);
+ cairo_restore (cr);
+
+ cairo_save (cr);
+ cairo_text_extents (cr, string, &extents);
+ cairo_set_source_rgba (cr, 1, 1, 1, 1.0);
+
+ switch (overlay->halign) {
+ case GST_CAIRO_TEXT_OVERLAY_HALIGN_LEFT:
+ x = overlay->xpad;
+ break;
+ case GST_CAIRO_TEXT_OVERLAY_HALIGN_CENTER:
+ x = (overlay->width - extents.width) / 2;
+ break;
+ case GST_CAIRO_TEXT_OVERLAY_HALIGN_RIGHT:
+ x = overlay->width - extents.width - overlay->xpad;
+ break;
+ default:
+ x = 0;
+ }
+ x += overlay->deltax;
+
+ overlay->text_x0 = x;
+ overlay->text_x1 = x + extents.x_advance;
+
+ overlay->text_dy = (extents.height + extents.y_bearing);
+ y = overlay->font_height - overlay->text_dy;
+
+ cairo_move_to (cr, x, y);
+ cairo_show_text (cr, string);
+ cairo_restore (cr);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ /* ----------- */
+
+ overlay->text_outline_image =
+ g_realloc (overlay->text_outline_image,
+ 4 * overlay->width * overlay->font_height);
+
+ surface = cairo_image_surface_create_for_data (overlay->text_outline_image,
+ CAIRO_FORMAT_ARGB32, overlay->width, overlay->font_height,
+ overlay->width * 4);
+
+ cr = cairo_create (surface);
+
+ cairo_select_font_face (cr, overlay->font, overlay->slant, overlay->weight);
+ cairo_set_font_size (cr, overlay->scale);
+
+ cairo_save (cr);
+ cairo_rectangle (cr, 0, 0, overlay->width, overlay->font_height);
+ cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_fill (cr);
+ cairo_restore (cr);
+
+ cairo_save (cr);
+ cairo_move_to (cr, x, y);
+ cairo_set_source_rgba (cr, 1, 1, 1, 1.0);
+ cairo_set_line_width (cr, 1.0);
+ cairo_text_path (cr, string);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+ g_free (string);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ overlay->need_render = FALSE;
+}
+
+static GstCaps *
+gst_text_overlay_getcaps (GstPad * pad)
+{
+ GstCairoTextOverlay *overlay;
+ GstPad *otherpad;
+ GstCaps *caps;
+
+ overlay = GST_CAIRO_TEXT_OVERLAY (gst_pad_get_parent (pad));
+
+ if (pad == overlay->srcpad)
+ otherpad = overlay->video_sinkpad;
+ else
+ otherpad = overlay->srcpad;
+
+ /* we can do what the peer can */
+ caps = gst_pad_peer_get_caps (otherpad);
+ if (caps) {
+ GstCaps *temp;
+ const GstCaps *templ;
+
+ GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps);
+
+ /* filtered against our padtemplate */
+ templ = gst_pad_get_pad_template_caps (otherpad);
+ GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
+ temp = gst_caps_intersect (caps, templ);
+ GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
+ gst_caps_unref (caps);
+ /* this is what we can do */
+ caps = temp;
+ } else {
+ /* no peer, our padtemplate is enough then */
+ caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+ }
+
+ GST_DEBUG_OBJECT (overlay, "returning %" GST_PTR_FORMAT, caps);
+
+ gst_object_unref (overlay);
+
+ return caps;
+}
+
+/* FIXME: upstream nego (e.g. when the video window is resized) */
+
+static gboolean
+gst_text_overlay_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstCairoTextOverlay *overlay;
+ GstStructure *structure;
+ gboolean ret = FALSE;
+ const GValue *fps;
+
+ if (!GST_PAD_IS_SINK (pad))
+ return TRUE;
+
+ g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
+
+ overlay = GST_CAIRO_TEXT_OVERLAY (gst_pad_get_parent (pad));
+
+ overlay->width = 0;
+ overlay->height = 0;
+ structure = gst_caps_get_structure (caps, 0);
+ fps = gst_structure_get_value (structure, "framerate");
+
+ if (gst_structure_get_int (structure, "width", &overlay->width) &&
+ gst_structure_get_int (structure, "height", &overlay->height) &&
+ fps != NULL) {
+ ret = gst_pad_set_caps (overlay->srcpad, caps);
+ }
+
+ overlay->fps_n = gst_value_get_fraction_numerator (fps);
+ overlay->fps_d = gst_value_get_fraction_denominator (fps);
+
+ gst_object_unref (overlay);
+
+ return ret;
+}
+
+static GstPadLinkReturn
+gst_text_overlay_text_pad_linked (GstPad * pad, GstPad * peer)
+{
+ GstCairoTextOverlay *overlay;
+
+ overlay = GST_CAIRO_TEXT_OVERLAY (GST_PAD_PARENT (pad));
+
+ GST_DEBUG_OBJECT (overlay, "Text pad linked");
+
+ if (overlay->text_collect_data == NULL) {
+ overlay->text_collect_data = gst_collect_pads_add_pad (overlay->collect,
+ overlay->text_sinkpad, sizeof (GstCollectData));
+ }
+
+ overlay->need_render = TRUE;
+
+ return GST_PAD_LINK_OK;
+}
+
+static void
+gst_text_overlay_text_pad_unlinked (GstPad * pad)
+{
+ GstCairoTextOverlay *overlay;
+
+ /* don't use gst_pad_get_parent() here, will deadlock */
+ overlay = GST_CAIRO_TEXT_OVERLAY (GST_PAD_PARENT (pad));
+
+ GST_DEBUG_OBJECT (overlay, "Text pad unlinked");
+
+ if (overlay->text_collect_data) {
+ gst_collect_pads_remove_pad (overlay->collect, overlay->text_sinkpad);
+ overlay->text_collect_data = NULL;
+ }
+
+ overlay->need_render = TRUE;
+}
+
+#define BOX_SHADING_VAL -80
+#define BOX_XPAD 6
+#define BOX_YPAD 6
+
+static inline void
+gst_text_overlay_shade_y (GstCairoTextOverlay * overlay, guchar * dest,
+ guint dest_stride, gint y0, gint y1)
+{
+ gint i, j, x0, x1;
+
+ x0 = CLAMP (overlay->text_x0 - BOX_XPAD, 0, overlay->width);
+ x1 = CLAMP (overlay->text_x1 + BOX_XPAD, 0, overlay->width);
+
+ y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
+ y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
+
+ for (i = y0; i < y1; ++i) {
+ for (j = x0; j < x1; ++j) {
+ gint y = dest[(i * dest_stride) + j] + BOX_SHADING_VAL;
+
+ dest[(i * dest_stride) + j] = CLAMP (y, 0, 255);
+ }
+ }
+}
+
+static inline void
+gst_text_overlay_blit_1 (GstCairoTextOverlay * overlay, guchar * dest,
+ guchar * text_image, gint val, guint dest_stride, gint y0)
+{
+ gint i, j;
+ gint x, a, y;
+ gint y1;
+
+ y = val;
+ y0 = MIN (y0, overlay->height);
+ y1 = MIN (y0 + overlay->font_height, overlay->height);
+
+ for (i = y0; i < y1; i++) {
+ for (j = 0; j < overlay->width; j++) {
+ x = dest[i * dest_stride + j];
+ a = text_image[4 * ((i - y0) * overlay->width + j) + 1];
+ dest[i * dest_stride + j] = (y * a + x * (255 - a)) / 255;
+ }
+ }
+}
+
+static inline void
+gst_text_overlay_blit_sub2x2 (GstCairoTextOverlay * overlay, guchar * dest,
+ guchar * text_image, gint val, guint dest_stride, gint y0)
+{
+ gint i, j;
+ gint x, a, y;
+ gint y1;
+
+ y0 = MIN (y0, overlay->height);
+ y1 = MIN (y0 + overlay->font_height, overlay->height);
+
+ y = val;
+
+ for (i = y0; i < y1; i += 2) {
+ for (j = 0; j < overlay->width; j += 2) {
+ x = dest[(i / 2) * dest_stride + j / 2];
+ a = (text_image[4 * ((i - y0) * overlay->width + j) + 1] +
+ text_image[4 * ((i - y0) * overlay->width + j + 1) + 1] +
+ text_image[4 * ((i - y0 + 1) * overlay->width + j) + 1] +
+ text_image[4 * ((i - y0 + 1) * overlay->width + j + 1) + 1] + 2) / 4;
+ dest[(i / 2) * dest_stride + j / 2] = (y * a + x * (255 - a)) / 255;
+ }
+ }
+}
+
+
+static GstFlowReturn
+gst_text_overlay_push_frame (GstCairoTextOverlay * overlay,
+ GstBuffer * video_frame)
+{
+ guchar *y, *u, *v;
+ gint ypos;
+
+ video_frame = gst_buffer_make_writable (video_frame);
+
+ switch (overlay->valign) {
+ case GST_CAIRO_TEXT_OVERLAY_VALIGN_BOTTOM:
+ ypos = overlay->height - overlay->font_height - overlay->ypad;
+ break;
+ case GST_CAIRO_TEXT_OVERLAY_VALIGN_BASELINE:
+ ypos = overlay->height - (overlay->font_height - overlay->text_dy)
+ - overlay->ypad;
+ break;
+ case GST_CAIRO_TEXT_OVERLAY_VALIGN_TOP:
+ ypos = overlay->ypad;
+ break;
+ default:
+ ypos = overlay->ypad;
+ break;
+ }
+
+ ypos += overlay->deltay;
+
+ y = GST_BUFFER_DATA (video_frame);
+ u = y + I420_U_OFFSET (overlay->width, overlay->height);
+ v = y + I420_V_OFFSET (overlay->width, overlay->height);
+
+ /* shaded background box */
+ if (overlay->want_shading) {
+ gst_text_overlay_shade_y (overlay,
+ y, I420_Y_ROWSTRIDE (overlay->width),
+ ypos + overlay->text_dy, ypos + overlay->font_height);
+ }
+
+ /* blit outline text on video image */
+ gst_text_overlay_blit_1 (overlay,
+ y,
+ overlay->text_outline_image, 0, I420_Y_ROWSTRIDE (overlay->width), ypos);
+ gst_text_overlay_blit_sub2x2 (overlay,
+ u,
+ overlay->text_outline_image, 128, I420_U_ROWSTRIDE (overlay->width),
+ ypos);
+ gst_text_overlay_blit_sub2x2 (overlay, v, overlay->text_outline_image, 128,
+ I420_V_ROWSTRIDE (overlay->width), ypos);
+
+ /* blit text on video image */
+ gst_text_overlay_blit_1 (overlay,
+ y,
+ overlay->text_fill_image, 255, I420_Y_ROWSTRIDE (overlay->width), ypos);
+ gst_text_overlay_blit_sub2x2 (overlay,
+ u,
+ overlay->text_fill_image, 128, I420_U_ROWSTRIDE (overlay->width), ypos);
+ gst_text_overlay_blit_sub2x2 (overlay,
+ v,
+ overlay->text_fill_image, 128, I420_V_ROWSTRIDE (overlay->width), ypos);
+
+ return gst_pad_push (overlay->srcpad, video_frame);
+}
+
+static void
+gst_text_overlay_pop_video (GstCairoTextOverlay * overlay)
+{
+ GstBuffer *buf;
+
+ buf = gst_collect_pads_pop (overlay->collect, overlay->video_collect_data);
+ g_return_if_fail (buf != NULL);
+ gst_buffer_unref (buf);
+}
+
+static void
+gst_text_overlay_pop_text (GstCairoTextOverlay * overlay)
+{
+ GstBuffer *buf;
+
+ if (overlay->text_collect_data) {
+ buf = gst_collect_pads_pop (overlay->collect, overlay->text_collect_data);
+ g_return_if_fail (buf != NULL);
+ gst_buffer_unref (buf);
+ }
+
+ overlay->need_render = TRUE;
+}
+
+/* This function is called when there is data on all pads */
+static GstFlowReturn
+gst_text_overlay_collected (GstCollectPads * pads, gpointer data)
+{
+ GstCairoTextOverlay *overlay;
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstClockTime now, txt_end, frame_end;
+ GstBuffer *video_frame = NULL;
+ GstBuffer *text_buf = NULL;
+ gchar *text;
+ gint text_len;
+
+ overlay = GST_CAIRO_TEXT_OVERLAY (data);
+
+ GST_DEBUG ("Collecting");
+
+ video_frame = gst_collect_pads_peek (overlay->collect,
+ overlay->video_collect_data);
+
+ /* send EOS if video stream EOSed regardless of text stream */
+ if (video_frame == NULL) {
+ GST_DEBUG ("Video stream at EOS");
+ if (overlay->text_collect_data) {
+ text_buf = gst_collect_pads_pop (overlay->collect,
+ overlay->text_collect_data);
+ }
+ gst_pad_push_event (overlay->srcpad, gst_event_new_eos ());
+ ret = GST_FLOW_UNEXPECTED;
+ goto done;
+ }
+
+ if (GST_BUFFER_TIMESTAMP (video_frame) == GST_CLOCK_TIME_NONE) {
+ g_warning ("%s: video frame has invalid timestamp", G_STRLOC);
+ }
+
+ now = GST_BUFFER_TIMESTAMP (video_frame);
+
+ if (GST_BUFFER_DURATION (video_frame) != GST_CLOCK_TIME_NONE) {
+ frame_end = now + GST_BUFFER_DURATION (video_frame);
+ } else if (overlay->fps_n > 0) {
+ frame_end = now + gst_util_uint64_scale_int (GST_SECOND,
+ overlay->fps_d, overlay->fps_n);
+ } else {
+ /* magic value, does not really matter since texts
+ * tend to span quite a few frames in practice anyway */
+ frame_end = now + GST_SECOND / 25;
+ }
+
+ GST_DEBUG ("Got video frame: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (now), GST_TIME_ARGS (frame_end));
+
+ /* text pad not linked? */
+ if (overlay->text_collect_data == NULL) {
+ GST_DEBUG ("Text pad not linked, rendering default text: '%s'",
+ GST_STR_NULL (overlay->default_text));
+ if (overlay->default_text && *overlay->default_text != '\0') {
+ gst_text_overlay_render_text (overlay, overlay->default_text, -1);
+ ret = gst_text_overlay_push_frame (overlay, video_frame);
+ } else {
+ ret = gst_pad_push (overlay->srcpad, video_frame);
+ }
+ gst_text_overlay_pop_video (overlay);
+ video_frame = NULL;
+ goto done;
+ }
+
+ text_buf = gst_collect_pads_peek (overlay->collect,
+ overlay->text_collect_data);
+
+ /* just push the video frame if the text stream has EOSed */
+ if (text_buf == NULL) {
+ GST_DEBUG ("Text pad EOSed, just pushing video frame as is");
+ ret = gst_pad_push (overlay->srcpad, video_frame);
+ gst_text_overlay_pop_video (overlay);
+ video_frame = NULL;
+ goto done;
+ }
+
+ /* if the text buffer isn't stamped right, pop it off the
+ * queue and display it for the current video frame only */
+ if (GST_BUFFER_TIMESTAMP (text_buf) == GST_CLOCK_TIME_NONE ||
+ GST_BUFFER_DURATION (text_buf) == GST_CLOCK_TIME_NONE) {
+ GST_WARNING ("Got text buffer with invalid time stamp or duration");
+ gst_text_overlay_pop_text (overlay);
+ GST_BUFFER_TIMESTAMP (text_buf) = now;
+ GST_BUFFER_DURATION (text_buf) = frame_end - now;
+ }
+
+ txt_end = GST_BUFFER_TIMESTAMP (text_buf) + GST_BUFFER_DURATION (text_buf);
+
+ GST_DEBUG ("Got text buffer: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (text_buf)), GST_TIME_ARGS (txt_end));
+
+ /* if the text buffer is too old, pop it off the
+ * queue and return so we get a new one next time */
+ if (txt_end < now) {
+ GST_DEBUG ("Text buffer too old, popping off the queue");
+ gst_text_overlay_pop_text (overlay);
+ ret = GST_FLOW_OK;
+ goto done;
+ }
+
+ /* if the video frame ends before the text even starts,
+ * just push it out as is and pop it off the queue */
+ if (frame_end < GST_BUFFER_TIMESTAMP (text_buf)) {
+ GST_DEBUG ("Video buffer before text, pushing out and popping off queue");
+ ret = gst_pad_push (overlay->srcpad, video_frame);
+ gst_text_overlay_pop_video (overlay);
+ video_frame = NULL;
+ goto done;
+ }
+
+ /* text duration overlaps video frame duration */
+ text = g_strndup ((gchar *) GST_BUFFER_DATA (text_buf),
+ GST_BUFFER_SIZE (text_buf));
+ g_strdelimit (text, "\n\r\t", ' ');
+ text_len = strlen (text);
+
+ if (text_len > 0) {
+ GST_DEBUG ("Rendering text '%*s'", text_len, text);;
+ gst_text_overlay_render_text (overlay, text, text_len);
+ } else {
+ GST_DEBUG ("No text to render (empty buffer)");
+ gst_text_overlay_render_text (overlay, " ", 1);
+ }
+
+ g_free (text);
+
+ gst_text_overlay_pop_video (overlay);
+ ret = gst_text_overlay_push_frame (overlay, video_frame);
+ video_frame = NULL;
+ goto done;
+
+done:
+ {
+ if (text_buf)
+ gst_buffer_unref (text_buf);
+
+ if (video_frame)
+ gst_buffer_unref (video_frame);
+
+ return ret;
+ }
+}
+
+static gboolean
+gst_text_overlay_src_event (GstPad * pad, GstEvent * event)
+{
+ GstCairoTextOverlay *overlay =
+ GST_CAIRO_TEXT_OVERLAY (gst_pad_get_parent (pad));
+ gboolean ret = TRUE;
+
+ /* forward events to the video sink, and, if it is linked, the text sink */
+ if (overlay->text_collect_data) {
+ gst_event_ref (event);
+ ret &= gst_pad_push_event (overlay->text_sinkpad, event);
+ }
+ ret &= gst_pad_push_event (overlay->video_sinkpad, event);
+
+ gst_object_unref (overlay);
+ return ret;
+}
+
+static gboolean
+gst_text_overlay_video_event (GstPad * pad, GstEvent * event)
+{
+ gboolean ret = FALSE;
+ GstCairoTextOverlay *overlay = NULL;
+
+ overlay = GST_CAIRO_TEXT_OVERLAY (gst_pad_get_parent (pad));
+
+ if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
+ GST_DEBUG_OBJECT (overlay,
+ "received new segment on video sink pad, forwarding");
+ gst_event_ref (event);
+ gst_pad_push_event (overlay->srcpad, event);
+ }
+
+ /* now GstCollectPads can take care of the rest, e.g. EOS */
+ ret = overlay->collect_event (pad, event);
+ gst_object_unref (overlay);
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_text_overlay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstCairoTextOverlay *overlay = GST_CAIRO_TEXT_OVERLAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_collect_pads_start (overlay->collect);
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ /* need to unblock the collectpads before calling the
+ * parent change_state so that streaming can finish */
+ gst_collect_pads_stop (overlay->collect);
+ break;
+ default:
+ break;
+ }
+
+ ret = parent_class->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ return ret;
+
+ switch (transition) {
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/cairo/gsttextoverlay.h b/ext/cairo/gsttextoverlay.h
new file mode 100644
index 0000000..dbb2154
--- /dev/null
+++ b/ext/cairo/gsttextoverlay.h
@@ -0,0 +1,90 @@
+
+#ifndef __GST_CAIRO_TEXT_OVERLAY_H__
+#define __GST_CAIRO_TEXT_OVERLAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstcollectpads.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CAIRO_TEXT_OVERLAY (gst_text_overlay_get_type())
+#define GST_CAIRO_TEXT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
+ GST_TYPE_CAIRO_TEXT_OVERLAY, GstCairoTextOverlay))
+#define GST_CAIRO_TEXT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\
+ GST_TYPE_CAIRO_TEXT_OVERLAY, GstCairoTextOverlayClass))
+#define GST_CAIRO_TEXT_OVERLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ GST_TYPE_CAIRO_TEXT_OVERLAY, GstCairoTextOverlayClass))
+#define GST_IS_CAIRO_TEXT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\
+ GST_TYPE_CAIRO_TEXT_OVERLAY))
+#define GST_IS_CAIRO_TEXT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
+ GST_TYPE_CAIRO_TEXT_OVERLAY))
+
+typedef struct _GstCairoTextOverlay GstCairoTextOverlay;
+typedef struct _GstCairoTextOverlayClass GstCairoTextOverlayClass;
+
+typedef enum _GstCairoTextOverlayVAlign GstCairoTextOverlayVAlign;
+typedef enum _GstCairoTextOverlayHAlign GstCairoTextOverlayHAlign;
+
+enum _GstCairoTextOverlayVAlign {
+ GST_CAIRO_TEXT_OVERLAY_VALIGN_BASELINE,
+ GST_CAIRO_TEXT_OVERLAY_VALIGN_BOTTOM,
+ GST_CAIRO_TEXT_OVERLAY_VALIGN_TOP
+};
+
+enum _GstCairoTextOverlayHAlign {
+ GST_CAIRO_TEXT_OVERLAY_HALIGN_LEFT,
+ GST_CAIRO_TEXT_OVERLAY_HALIGN_CENTER,
+ GST_CAIRO_TEXT_OVERLAY_HALIGN_RIGHT
+};
+
+
+struct _GstCairoTextOverlay {
+ GstElement element;
+
+ GstPad *video_sinkpad;
+ GstPad *text_sinkpad;
+ GstPad *srcpad;
+
+ GstCollectPads *collect;
+ GstCollectData *video_collect_data;
+ GstCollectData *text_collect_data;
+ GstPadEventFunction collect_event;
+
+ gint width;
+ gint height;
+ gint fps_n;
+ gint fps_d;
+
+ GstCairoTextOverlayVAlign valign;
+ GstCairoTextOverlayHAlign halign;
+ gint xpad;
+ gint ypad;
+ gint deltax;
+ gint deltay;
+ gchar *default_text;
+ gboolean want_shading;
+
+ guchar *text_fill_image;
+ guchar *text_outline_image;
+ gint font_height;
+ gint text_x0, text_x1; /* start/end x position of text */
+ gint text_dy;
+
+ gboolean need_render;
+
+ gchar *font;
+ gint slant;
+ gint weight;
+ gdouble scale;
+ gboolean silent;
+};
+
+struct _GstCairoTextOverlayClass {
+ GstElementClass parent_class;
+};
+
+GType gst_text_overlay_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_CAIRO_TEXT_OVERLAY_H */
diff --git a/ext/cairo/gsttimeoverlay.c b/ext/cairo/gsttimeoverlay.c
new file mode 100644
index 0000000..10973b1
--- /dev/null
+++ b/ext/cairo/gsttimeoverlay.c
@@ -0,0 +1,316 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-cairotimeoverlay
+ *
+ * cairotimeoverlay renders the buffer timestamp for each frame on top of
+ * the frame.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch videotestsrc ! cairotimeoverlay ! autovideosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/math-compat.h>
+
+#include <gsttimeoverlay.h>
+
+#include <string.h>
+
+#include <cairo.h>
+
+#include <gst/video/video.h>
+
+static GstStaticPadTemplate gst_cairo_time_overlay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
+ );
+
+static GstStaticPadTemplate gst_cairo_time_overlay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
+ );
+
+static GstBaseTransformClass *parent_class = NULL;
+
+static void
+gst_cairo_time_overlay_update_font_height (GstCairoTimeOverlay * timeoverlay)
+{
+ gint width, height;
+ cairo_surface_t *font_surface;
+ cairo_t *font_cairo;
+ cairo_font_extents_t font_extents;
+
+ width = timeoverlay->width;
+ height = timeoverlay->height;
+
+ font_surface =
+ cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ font_cairo = cairo_create (font_surface);
+ cairo_surface_destroy (font_surface);
+ font_surface = NULL;
+
+ cairo_select_font_face (font_cairo, "monospace", 0, 0);
+ cairo_set_font_size (font_cairo, 20);
+ cairo_font_extents (font_cairo, &font_extents);
+ timeoverlay->text_height = font_extents.height;
+ GST_DEBUG_OBJECT (timeoverlay, "font height is %f", font_extents.height);
+ cairo_destroy (font_cairo);
+ font_cairo = NULL;
+}
+
+static gboolean
+gst_cairo_time_overlay_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
+ GstCaps * outcaps)
+{
+ GstCairoTimeOverlay *filter = GST_CAIRO_TIME_OVERLAY (btrans);
+ GstStructure *structure;
+ gboolean ret = FALSE;
+
+ structure = gst_caps_get_structure (incaps, 0);
+
+ if (gst_structure_get_int (structure, "width", &filter->width) &&
+ gst_structure_get_int (structure, "height", &filter->height)) {
+ gst_cairo_time_overlay_update_font_height (filter);
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+/* Useful macros */
+#define GST_VIDEO_I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
+#define GST_VIDEO_I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
+#define GST_VIDEO_I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
+
+#define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
+#define GST_VIDEO_I420_U_OFFSET(w,h) (GST_VIDEO_I420_Y_OFFSET(w,h)+(GST_VIDEO_I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
+#define GST_VIDEO_I420_V_OFFSET(w,h) (GST_VIDEO_I420_U_OFFSET(w,h)+(GST_VIDEO_I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
+
+#define GST_VIDEO_I420_SIZE(w,h) (GST_VIDEO_I420_V_OFFSET(w,h)+(GST_VIDEO_I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
+
+static gboolean
+gst_cairo_time_overlay_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
+ guint * size)
+{
+ GstCairoTimeOverlay *filter;
+ GstStructure *structure;
+ gboolean ret = FALSE;
+ gint width, height;
+
+ filter = GST_CAIRO_TIME_OVERLAY (btrans);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (gst_structure_get_int (structure, "width", &width) &&
+ gst_structure_get_int (structure, "height", &height)) {
+ *size = GST_VIDEO_I420_SIZE (width, height);
+ ret = TRUE;
+ GST_DEBUG_OBJECT (filter, "our frame size is %d bytes (%dx%d)", *size,
+ width, height);
+ }
+
+ return ret;
+}
+
+static char *
+gst_cairo_time_overlay_print_smpte_time (guint64 time)
+{
+ int hours;
+ int minutes;
+ int seconds;
+ int ms;
+ double x;
+
+ x = rint (gst_util_guint64_to_gdouble (time + 500000) * 1e-6);
+
+ hours = floor (x / (60 * 60 * 1000));
+ x -= hours * 60 * 60 * 1000;
+ minutes = floor (x / (60 * 1000));
+ x -= minutes * 60 * 1000;
+ seconds = floor (x / (1000));
+ x -= seconds * 1000;
+ ms = rint (x);
+
+ return g_strdup_printf ("%02d:%02d:%02d.%03d", hours, minutes, seconds, ms);
+}
+
+
+static GstFlowReturn
+gst_cairo_time_overlay_transform (GstBaseTransform * trans, GstBuffer * in,
+ GstBuffer * out)
+{
+ GstCairoTimeOverlay *timeoverlay;
+ int width;
+ int height;
+ int b_width;
+ int stride_y, stride_u, stride_v;
+ char *string;
+ int i, j;
+ unsigned char *image;
+ cairo_text_extents_t extents;
+ guint8 *dest, *src;
+ cairo_surface_t *font_surface;
+ cairo_t *text_cairo;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ timeoverlay = GST_CAIRO_TIME_OVERLAY (trans);
+
+ gst_buffer_copy_metadata (out, in, GST_BUFFER_COPY_TIMESTAMPS);
+
+ src = GST_BUFFER_DATA (in);
+ dest = GST_BUFFER_DATA (out);
+
+ width = timeoverlay->width;
+ height = timeoverlay->height;
+
+ /* create surface for font rendering */
+ /* FIXME: preparation of the surface could also be done once when settings
+ * change */
+ image = g_malloc (4 * width * timeoverlay->text_height);
+
+ font_surface =
+ cairo_image_surface_create_for_data (image, CAIRO_FORMAT_ARGB32, width,
+ timeoverlay->text_height, width * 4);
+ text_cairo = cairo_create (font_surface);
+ cairo_surface_destroy (font_surface);
+ font_surface = NULL;
+
+ /* we draw a rectangle because the compositing on the buffer below
+ * doesn't do alpha */
+ cairo_save (text_cairo);
+ cairo_rectangle (text_cairo, 0, 0, width, timeoverlay->text_height);
+ cairo_set_source_rgba (text_cairo, 0, 0, 0, 1);
+ cairo_set_operator (text_cairo, CAIRO_OPERATOR_SOURCE);
+ cairo_fill (text_cairo);
+ cairo_restore (text_cairo);
+
+ string = gst_cairo_time_overlay_print_smpte_time (GST_BUFFER_TIMESTAMP (in));
+ cairo_save (text_cairo);
+ cairo_select_font_face (text_cairo, "monospace", 0, 0);
+ cairo_set_font_size (text_cairo, 20);
+ cairo_text_extents (text_cairo, string, &extents);
+ cairo_set_source_rgb (text_cairo, 1, 1, 1);
+ cairo_move_to (text_cairo, 0, timeoverlay->text_height - 2);
+ cairo_show_text (text_cairo, string);
+ g_free (string);
+
+ cairo_restore (text_cairo);
+
+ /* blend width; should retain a max text width so it doesn't jitter */
+ b_width = extents.width;
+ if (b_width > width)
+ b_width = width;
+
+ stride_y = GST_VIDEO_I420_Y_ROWSTRIDE (width);
+ stride_u = GST_VIDEO_I420_U_ROWSTRIDE (width);
+ stride_v = GST_VIDEO_I420_V_ROWSTRIDE (width);
+
+ memcpy (dest, src, GST_BUFFER_SIZE (in));
+ for (i = 0; i < timeoverlay->text_height; i++) {
+ for (j = 0; j < b_width; j++) {
+ ((unsigned char *) dest)[i * stride_y + j] =
+ image[(i * width + j) * 4 + 0];
+ }
+ }
+ for (i = 0; i < timeoverlay->text_height / 2; i++) {
+ memset (dest + GST_VIDEO_I420_U_OFFSET (width, height) + i * stride_u, 128,
+ b_width / 2);
+ memset (dest + GST_VIDEO_I420_V_OFFSET (width, height) + i * stride_v, 128,
+ b_width / 2);
+ }
+
+ cairo_destroy (text_cairo);
+ text_cairo = NULL;
+ g_free (image);
+
+ return ret;
+}
+
+static void
+gst_cairo_time_overlay_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details_simple (element_class, "Time overlay",
+ "Filter/Editor/Video",
+ "Overlays the time on a video stream", "David Schleef <ds@schleef.org>");
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_cairo_time_overlay_sink_template);
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_cairo_time_overlay_src_template);
+}
+
+static void
+gst_cairo_time_overlay_class_init (gpointer klass, gpointer class_data)
+{
+ GstBaseTransformClass *trans_class;
+
+ trans_class = (GstBaseTransformClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_cairo_time_overlay_set_caps);
+ trans_class->get_unit_size =
+ GST_DEBUG_FUNCPTR (gst_cairo_time_overlay_get_unit_size);
+ trans_class->transform = GST_DEBUG_FUNCPTR (gst_cairo_time_overlay_transform);
+}
+
+static void
+gst_cairo_time_overlay_init (GTypeInstance * instance, gpointer g_class)
+{
+}
+
+GType
+gst_cairo_time_overlay_get_type (void)
+{
+ static GType cairo_time_overlay_type = 0;
+
+ if (!cairo_time_overlay_type) {
+ static const GTypeInfo cairo_time_overlay_info = {
+ sizeof (GstCairoTimeOverlayClass),
+ gst_cairo_time_overlay_base_init,
+ NULL,
+ gst_cairo_time_overlay_class_init,
+ NULL,
+ NULL,
+ sizeof (GstCairoTimeOverlay),
+ 0,
+ gst_cairo_time_overlay_init,
+ };
+
+ cairo_time_overlay_type = g_type_register_static (GST_TYPE_BASE_TRANSFORM,
+ "GstCairoTimeOverlay", &cairo_time_overlay_info, 0);
+ }
+ return cairo_time_overlay_type;
+}
diff --git a/ext/cairo/gsttimeoverlay.h b/ext/cairo/gsttimeoverlay.h
new file mode 100644
index 0000000..ff0936e
--- /dev/null
+++ b/ext/cairo/gsttimeoverlay.h
@@ -0,0 +1,59 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CAIRO_TIME_OVERLAY_H__
+#define __GST_CAIRO_TIME_OVERLAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <cairo.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CAIRO_TIME_OVERLAY \
+ (gst_cairo_time_overlay_get_type())
+#define GST_CAIRO_TIME_OVERLAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAIRO_TIME_OVERLAY,GstCairoTimeOverlay))
+#define GST_CAIRO_TIME_OVERLAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAIRO_TIME_OVERLAY,GstCairoTimeOverlayClass))
+#define GST_IS_CAIRO_TIME_OVERLAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAIRO_TIME_OVERLAY))
+#define GST_IS_CAIRO_TIME_OVERLAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAIRO_TIME_OVERLAY))
+
+typedef struct _GstCairoTimeOverlay {
+ GstBaseTransform basetransform;
+
+ gint width, height;
+
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ int text_height;
+
+} GstCairoTimeOverlay;
+
+typedef struct _GstCairoTimeOverlayClass {
+ GstBaseTransformClass parent_class;
+} GstCairoTimeOverlayClass;
+
+GType gst_cairo_time_overlay_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_CAIRO_TIME_OVERLAY_H__ */
diff --git a/ext/dv/Makefile.am b/ext/dv/Makefile.am
new file mode 100644
index 0000000..e63154d
--- /dev/null
+++ b/ext/dv/Makefile.am
@@ -0,0 +1,20 @@
+plugin_LTLIBRARIES = libgstdv.la
+
+libgstdv_la_SOURCES = gstdv.c gstdvdec.c gstdvdemux.c gstsmptetimecode.c
+libgstdv_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(LIBDV_CFLAGS)
+libgstdv_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) $(GST_LIBS) $(LIBDV_LIBS)
+libgstdv_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstdv_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstdvdemux.h gstdvdec.h gstsmptetimecode.h
+
+EXTRA_DIST = NOTES
+
+noinst_PROGRAMS = smpte_test
+
+smpte_test_SOURCES = smpte_test.c gstsmptetimecode.c
+smpte_test_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LIBDV_CFLAGS)
+smpte_test_LDADD = $(GST_BASE_LIBS) $(GST_LIBS)
+
diff --git a/ext/dv/Makefile.in b/ext/dv/Makefile.in
new file mode 100644
index 0000000..bb9c93e
--- /dev/null
+++ b/ext/dv/Makefile.in
@@ -0,0 +1,890 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = smpte_test$(EXEEXT)
+subdir = ext/dv
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstdv_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libgstdv_la_OBJECTS = libgstdv_la-gstdv.lo libgstdv_la-gstdvdec.lo \
+ libgstdv_la-gstdvdemux.lo libgstdv_la-gstsmptetimecode.lo
+libgstdv_la_OBJECTS = $(am_libgstdv_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstdv_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstdv_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstdv_la_CFLAGS) $(CFLAGS) $(libgstdv_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+PROGRAMS = $(noinst_PROGRAMS)
+am_smpte_test_OBJECTS = smpte_test-smpte_test.$(OBJEXT) \
+ smpte_test-gstsmptetimecode.$(OBJEXT)
+smpte_test_OBJECTS = $(am_smpte_test_OBJECTS)
+smpte_test_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+smpte_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(smpte_test_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstdv_la_SOURCES) $(smpte_test_SOURCES)
+DIST_SOURCES = $(libgstdv_la_SOURCES) $(smpte_test_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstdv.la
+libgstdv_la_SOURCES = gstdv.c gstdvdec.c gstdvdemux.c gstsmptetimecode.c
+libgstdv_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(LIBDV_CFLAGS)
+libgstdv_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) $(GST_LIBS) $(LIBDV_LIBS)
+
+libgstdv_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstdv_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = gstdvdemux.h gstdvdec.h gstsmptetimecode.h
+EXTRA_DIST = NOTES
+smpte_test_SOURCES = smpte_test.c gstsmptetimecode.c
+smpte_test_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LIBDV_CFLAGS)
+smpte_test_LDADD = $(GST_BASE_LIBS) $(GST_LIBS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/dv/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/dv/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstdv.la: $(libgstdv_la_OBJECTS) $(libgstdv_la_DEPENDENCIES) $(EXTRA_libgstdv_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstdv_la_LINK) -rpath $(plugindir) $(libgstdv_la_OBJECTS) $(libgstdv_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+smpte_test$(EXEEXT): $(smpte_test_OBJECTS) $(smpte_test_DEPENDENCIES) $(EXTRA_smpte_test_DEPENDENCIES)
+ @rm -f smpte_test$(EXEEXT)
+ $(AM_V_CCLD)$(smpte_test_LINK) $(smpte_test_OBJECTS) $(smpte_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstdv_la-gstdv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstdv_la-gstdvdec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstdv_la-gstdvdemux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstdv_la-gstsmptetimecode.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smpte_test-gstsmptetimecode.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smpte_test-smpte_test.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstdv_la-gstdv.lo: gstdv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdv_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdv_la_CFLAGS) $(CFLAGS) -MT libgstdv_la-gstdv.lo -MD -MP -MF $(DEPDIR)/libgstdv_la-gstdv.Tpo -c -o libgstdv_la-gstdv.lo `test -f 'gstdv.c' || echo '$(srcdir)/'`gstdv.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstdv_la-gstdv.Tpo $(DEPDIR)/libgstdv_la-gstdv.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstdv.c' object='libgstdv_la-gstdv.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdv_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdv_la_CFLAGS) $(CFLAGS) -c -o libgstdv_la-gstdv.lo `test -f 'gstdv.c' || echo '$(srcdir)/'`gstdv.c
+
+libgstdv_la-gstdvdec.lo: gstdvdec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdv_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdv_la_CFLAGS) $(CFLAGS) -MT libgstdv_la-gstdvdec.lo -MD -MP -MF $(DEPDIR)/libgstdv_la-gstdvdec.Tpo -c -o libgstdv_la-gstdvdec.lo `test -f 'gstdvdec.c' || echo '$(srcdir)/'`gstdvdec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstdv_la-gstdvdec.Tpo $(DEPDIR)/libgstdv_la-gstdvdec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstdvdec.c' object='libgstdv_la-gstdvdec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdv_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdv_la_CFLAGS) $(CFLAGS) -c -o libgstdv_la-gstdvdec.lo `test -f 'gstdvdec.c' || echo '$(srcdir)/'`gstdvdec.c
+
+libgstdv_la-gstdvdemux.lo: gstdvdemux.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdv_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdv_la_CFLAGS) $(CFLAGS) -MT libgstdv_la-gstdvdemux.lo -MD -MP -MF $(DEPDIR)/libgstdv_la-gstdvdemux.Tpo -c -o libgstdv_la-gstdvdemux.lo `test -f 'gstdvdemux.c' || echo '$(srcdir)/'`gstdvdemux.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstdv_la-gstdvdemux.Tpo $(DEPDIR)/libgstdv_la-gstdvdemux.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstdvdemux.c' object='libgstdv_la-gstdvdemux.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdv_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdv_la_CFLAGS) $(CFLAGS) -c -o libgstdv_la-gstdvdemux.lo `test -f 'gstdvdemux.c' || echo '$(srcdir)/'`gstdvdemux.c
+
+libgstdv_la-gstsmptetimecode.lo: gstsmptetimecode.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdv_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdv_la_CFLAGS) $(CFLAGS) -MT libgstdv_la-gstsmptetimecode.lo -MD -MP -MF $(DEPDIR)/libgstdv_la-gstsmptetimecode.Tpo -c -o libgstdv_la-gstsmptetimecode.lo `test -f 'gstsmptetimecode.c' || echo '$(srcdir)/'`gstsmptetimecode.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstdv_la-gstsmptetimecode.Tpo $(DEPDIR)/libgstdv_la-gstsmptetimecode.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsmptetimecode.c' object='libgstdv_la-gstsmptetimecode.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdv_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdv_la_CFLAGS) $(CFLAGS) -c -o libgstdv_la-gstsmptetimecode.lo `test -f 'gstsmptetimecode.c' || echo '$(srcdir)/'`gstsmptetimecode.c
+
+smpte_test-smpte_test.o: smpte_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(smpte_test_CFLAGS) $(CFLAGS) -MT smpte_test-smpte_test.o -MD -MP -MF $(DEPDIR)/smpte_test-smpte_test.Tpo -c -o smpte_test-smpte_test.o `test -f 'smpte_test.c' || echo '$(srcdir)/'`smpte_test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/smpte_test-smpte_test.Tpo $(DEPDIR)/smpte_test-smpte_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='smpte_test.c' object='smpte_test-smpte_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(smpte_test_CFLAGS) $(CFLAGS) -c -o smpte_test-smpte_test.o `test -f 'smpte_test.c' || echo '$(srcdir)/'`smpte_test.c
+
+smpte_test-smpte_test.obj: smpte_test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(smpte_test_CFLAGS) $(CFLAGS) -MT smpte_test-smpte_test.obj -MD -MP -MF $(DEPDIR)/smpte_test-smpte_test.Tpo -c -o smpte_test-smpte_test.obj `if test -f 'smpte_test.c'; then $(CYGPATH_W) 'smpte_test.c'; else $(CYGPATH_W) '$(srcdir)/smpte_test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/smpte_test-smpte_test.Tpo $(DEPDIR)/smpte_test-smpte_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='smpte_test.c' object='smpte_test-smpte_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(smpte_test_CFLAGS) $(CFLAGS) -c -o smpte_test-smpte_test.obj `if test -f 'smpte_test.c'; then $(CYGPATH_W) 'smpte_test.c'; else $(CYGPATH_W) '$(srcdir)/smpte_test.c'; fi`
+
+smpte_test-gstsmptetimecode.o: gstsmptetimecode.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(smpte_test_CFLAGS) $(CFLAGS) -MT smpte_test-gstsmptetimecode.o -MD -MP -MF $(DEPDIR)/smpte_test-gstsmptetimecode.Tpo -c -o smpte_test-gstsmptetimecode.o `test -f 'gstsmptetimecode.c' || echo '$(srcdir)/'`gstsmptetimecode.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/smpte_test-gstsmptetimecode.Tpo $(DEPDIR)/smpte_test-gstsmptetimecode.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsmptetimecode.c' object='smpte_test-gstsmptetimecode.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(smpte_test_CFLAGS) $(CFLAGS) -c -o smpte_test-gstsmptetimecode.o `test -f 'gstsmptetimecode.c' || echo '$(srcdir)/'`gstsmptetimecode.c
+
+smpte_test-gstsmptetimecode.obj: gstsmptetimecode.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(smpte_test_CFLAGS) $(CFLAGS) -MT smpte_test-gstsmptetimecode.obj -MD -MP -MF $(DEPDIR)/smpte_test-gstsmptetimecode.Tpo -c -o smpte_test-gstsmptetimecode.obj `if test -f 'gstsmptetimecode.c'; then $(CYGPATH_W) 'gstsmptetimecode.c'; else $(CYGPATH_W) '$(srcdir)/gstsmptetimecode.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/smpte_test-gstsmptetimecode.Tpo $(DEPDIR)/smpte_test-gstsmptetimecode.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsmptetimecode.c' object='smpte_test-gstsmptetimecode.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(smpte_test_CFLAGS) $(CFLAGS) -c -o smpte_test-gstsmptetimecode.obj `if test -f 'gstsmptetimecode.c'; then $(CYGPATH_W) 'gstsmptetimecode.c'; else $(CYGPATH_W) '$(srcdir)/gstsmptetimecode.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+ clean-pluginLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstPROGRAMS clean-pluginLTLIBRARIES \
+ ctags distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pluginLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/dv/NOTES b/ext/dv/NOTES
new file mode 100644
index 0000000..8421159
--- /dev/null
+++ b/ext/dv/NOTES
@@ -0,0 +1,13 @@
+Packets come from 1394 480 bytes at a time. This is not a video segment
+length. This causes problems, since a packet boundary crossing a video
+segment can split a video segment if we lose an iso packet. We can
+recover from this, sorta, with significant changes to the parser. We have
+to deal with the idea that a) some macroblocks just don't exist (we have
+zero's for them) and b) when any of the 5 macroblocks doesn't exist, we
+can't do pass 3.
+
+Since things are bitstream-based, we can deal with this, but we have to
+add a layer of code that tries to save time (maybe) by not decoding things
+that don't exist. Not sure how this is gonna work with the parse code
+being based on video segments, and not easily splittable into
+macroblock-level parsing (or is it?).
diff --git a/ext/dv/gstdv.c b/ext/dv/gstdv.c
new file mode 100644
index 0000000..970c5d1
--- /dev/null
+++ b/ext/dv/gstdv.c
@@ -0,0 +1,48 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * <2005> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstdvdec.h"
+#include "gstdvdemux.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ dv_init (0, 0);
+
+ if (!gst_element_register (plugin, "dvdemux", GST_RANK_PRIMARY,
+ gst_dvdemux_get_type ()))
+ return FALSE;
+
+ if (!gst_element_register (plugin, "dvdec", GST_RANK_MARGINAL,
+ gst_dvdec_get_type ()))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "dv",
+ "DV demuxer and decoder based on libdv (libdv.sf.net)",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/ext/dv/gstdvdec.c b/ext/dv/gstdvdec.c
new file mode 100644
index 0000000..e425744
--- /dev/null
+++ b/ext/dv/gstdvdec.c
@@ -0,0 +1,617 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * <2005> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-dvdec
+ *
+ * dvdec decodes DV video into raw video. The element expects a full DV frame
+ * as input, which is 120000 bytes for NTSC and 144000 for PAL video.
+ *
+ * This element can perform simple frame dropping with the #GstDVDec:drop-factor
+ * property. Setting this property to a value N > 1 will only decode every
+ * Nth frame.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch filesrc location=test.dv ! dvdemux name=demux ! dvdec ! xvimagesink
+ * ]| This pipeline decodes and renders the raw DV stream to a videosink.
+ * </refsect2>
+ *
+ * Last reviewed on 2006-02-28 (0.10.3)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+#include <math.h>
+#include <gst/video/video.h>
+
+#include "gstdvdec.h"
+
+/* sizes of one input buffer */
+#define NTSC_HEIGHT 480
+#define NTSC_BUFFER 120000
+#define NTSC_FRAMERATE_NUMERATOR 30000
+#define NTSC_FRAMERATE_DENOMINATOR 1001
+
+#define PAL_HEIGHT 576
+#define PAL_BUFFER 144000
+#define PAL_FRAMERATE_NUMERATOR 25
+#define PAL_FRAMERATE_DENOMINATOR 1
+
+#define PAL_NORMAL_PAR_X 59
+#define PAL_NORMAL_PAR_Y 54
+#define PAL_WIDE_PAR_X 118
+#define PAL_WIDE_PAR_Y 81
+
+#define NTSC_NORMAL_PAR_X 10
+#define NTSC_NORMAL_PAR_Y 11
+#define NTSC_WIDE_PAR_X 40
+#define NTSC_WIDE_PAR_Y 33
+
+#define DV_DEFAULT_QUALITY DV_QUALITY_BEST
+#define DV_DEFAULT_DECODE_NTH 1
+
+GST_DEBUG_CATEGORY_STATIC (dvdec_debug);
+#define GST_CAT_DEFAULT dvdec_debug
+
+enum
+{
+ PROP_0,
+ PROP_CLAMP_LUMA,
+ PROP_CLAMP_CHROMA,
+ PROP_QUALITY,
+ PROP_DECODE_NTH
+};
+
+const gint qualities[] = {
+ DV_QUALITY_DC,
+ DV_QUALITY_AC_1,
+ DV_QUALITY_AC_2,
+ DV_QUALITY_DC | DV_QUALITY_COLOR,
+ DV_QUALITY_AC_1 | DV_QUALITY_COLOR,
+ DV_QUALITY_AC_2 | DV_QUALITY_COLOR
+};
+
+static GstStaticPadTemplate sink_temp = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-dv, systemstream = (boolean) false")
+ );
+
+static GstStaticPadTemplate src_temp = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw-yuv, "
+ "format = (fourcc) YUY2, "
+ "width = (int) 720, "
+ "framerate = (fraction) [ 1/1, 60/1 ];"
+ "video/x-raw-rgb, "
+ "bpp = (int) 32, "
+ "depth = (int) 24, "
+ "endianness = (int) " G_STRINGIFY (G_BIG_ENDIAN) ", "
+ "red_mask = (int) 0x0000ff00, "
+ "green_mask = (int) 0x00ff0000, "
+ "blue_mask = (int) 0xff000000, "
+ "width = (int) 720, "
+ "framerate = (fraction) [ 1/1, 60/1 ];"
+ "video/x-raw-rgb, "
+ "bpp = (int) 24, "
+ "depth = (int) 24, "
+ "endianness = (int) " G_STRINGIFY (G_BIG_ENDIAN) ", "
+ "red_mask = (int) 0x00ff0000, "
+ "green_mask = (int) 0x0000ff00, "
+ "blue_mask = (int) 0x000000ff, "
+ "width = (int) 720, " "framerate = (fraction) [ 1/1, 60/1 ]")
+ );
+
+#define GST_TYPE_DVDEC_QUALITY (gst_dvdec_quality_get_type())
+static GType
+gst_dvdec_quality_get_type (void)
+{
+ static GType qtype = 0;
+
+ if (qtype == 0) {
+ static const GEnumValue values[] = {
+ {0, "Monochrome, DC (Fastest)", "fastest"},
+ {1, "Monochrome, first AC coefficient", "monochrome-ac"},
+ {2, "Monochrome, highest quality", "monochrome-best"},
+ {3, "Colour, DC, fastest", "colour-fastest"},
+ {4, "Colour, using only the first AC coefficient", "colour-ac"},
+ {5, "Highest quality colour decoding", "best"},
+ {0, NULL, NULL},
+ };
+
+ qtype = g_enum_register_static ("GstDVDecQualityEnum", values);
+ }
+ return qtype;
+}
+
+GST_BOILERPLATE (GstDVDec, gst_dvdec, GstElement, GST_TYPE_ELEMENT);
+
+static void gst_dvdec_finalize (GObject * object);
+static gboolean gst_dvdec_sink_setcaps (GstPad * pad, GstCaps * caps);
+static GstFlowReturn gst_dvdec_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_dvdec_sink_event (GstPad * pad, GstEvent * event);
+
+static GstStateChangeReturn gst_dvdec_change_state (GstElement * element,
+ GstStateChange transition);
+
+static void gst_dvdec_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_dvdec_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void
+gst_dvdec_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class, &sink_temp);
+ gst_element_class_add_static_pad_template (element_class, &src_temp);
+
+ gst_element_class_set_details_simple (element_class, "DV video decoder",
+ "Codec/Decoder/Video",
+ "Uses libdv to decode DV video (smpte314) (libdv.sourceforge.net)",
+ "Erik Walthinsen <omega@cse.ogi.edu>," "Wim Taymans <wim@fluendo.com>");
+
+ GST_DEBUG_CATEGORY_INIT (dvdec_debug, "dvdec", 0, "DV decoding element");
+}
+
+static void
+gst_dvdec_class_init (GstDVDecClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = gst_dvdec_finalize;
+ gobject_class->set_property = gst_dvdec_set_property;
+ gobject_class->get_property = gst_dvdec_get_property;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CLAMP_LUMA,
+ g_param_spec_boolean ("clamp-luma", "Clamp luma", "Clamp luma",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CLAMP_CHROMA,
+ g_param_spec_boolean ("clamp-chroma", "Clamp chroma", "Clamp chroma",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
+ g_param_spec_enum ("quality", "Quality", "Decoding quality",
+ GST_TYPE_DVDEC_QUALITY, DV_DEFAULT_QUALITY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DECODE_NTH,
+ g_param_spec_int ("drop-factor", "Drop Factor", "Only decode Nth frame",
+ 1, G_MAXINT, DV_DEFAULT_DECODE_NTH,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gstelement_class->change_state = gst_dvdec_change_state;
+}
+
+static void
+gst_dvdec_init (GstDVDec * dvdec, GstDVDecClass * g_class)
+{
+ dvdec->sinkpad = gst_pad_new_from_static_template (&sink_temp, "sink");
+ gst_pad_set_setcaps_function (dvdec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_dvdec_sink_setcaps));
+ gst_pad_set_chain_function (dvdec->sinkpad, gst_dvdec_chain);
+ gst_pad_set_event_function (dvdec->sinkpad, gst_dvdec_sink_event);
+ gst_element_add_pad (GST_ELEMENT (dvdec), dvdec->sinkpad);
+
+ dvdec->srcpad = gst_pad_new_from_static_template (&src_temp, "src");
+ gst_pad_use_fixed_caps (dvdec->srcpad);
+ gst_element_add_pad (GST_ELEMENT (dvdec), dvdec->srcpad);
+
+ dvdec->framerate_numerator = 0;
+ dvdec->framerate_denominator = 0;
+ dvdec->wide = FALSE;
+ dvdec->drop_factor = 1;
+
+ dvdec->clamp_luma = FALSE;
+ dvdec->clamp_chroma = FALSE;
+ dvdec->quality = DV_DEFAULT_QUALITY;
+ dvdec->segment = gst_segment_new ();
+}
+
+static void
+gst_dvdec_finalize (GObject * object)
+{
+ GstDVDec *dvdec = GST_DVDEC (object);
+
+ gst_segment_free (dvdec->segment);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_dvdec_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstDVDec *dvdec;
+ GstStructure *s;
+ const GValue *par = NULL, *rate = NULL;
+
+ dvdec = GST_DVDEC (gst_pad_get_parent (pad));
+
+ /* first parse the caps */
+ s = gst_caps_get_structure (caps, 0);
+
+ /* we allow framerate and PAR to be overwritten. framerate is mandatory. */
+ if (!(rate = gst_structure_get_value (s, "framerate")))
+ goto no_framerate;
+ par = gst_structure_get_value (s, "pixel-aspect-ratio");
+
+ if (par) {
+ dvdec->par_x = gst_value_get_fraction_numerator (par);
+ dvdec->par_y = gst_value_get_fraction_denominator (par);
+ dvdec->need_par = FALSE;
+ } else {
+ dvdec->par_x = 0;
+ dvdec->par_y = 0;
+ dvdec->need_par = TRUE;
+ }
+ dvdec->framerate_numerator = gst_value_get_fraction_numerator (rate);
+ dvdec->framerate_denominator = gst_value_get_fraction_denominator (rate);
+ dvdec->sink_negotiated = TRUE;
+ dvdec->src_negotiated = FALSE;
+
+ gst_object_unref (dvdec);
+
+ return TRUE;
+
+ /* ERRORS */
+no_framerate:
+ {
+ GST_DEBUG_OBJECT (dvdec, "no framerate specified in caps");
+ gst_object_unref (dvdec);
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_dvdec_src_negotiate (GstDVDec * dvdec)
+{
+ GstCaps *othercaps;
+
+ /* no PAR was specified in input, derive from encoded data */
+ if (dvdec->need_par) {
+ if (dvdec->PAL) {
+ if (dvdec->wide) {
+ dvdec->par_x = PAL_WIDE_PAR_X;
+ dvdec->par_y = PAL_WIDE_PAR_Y;
+ } else {
+ dvdec->par_x = PAL_NORMAL_PAR_X;
+ dvdec->par_y = PAL_NORMAL_PAR_Y;
+ }
+ } else {
+ if (dvdec->wide) {
+ dvdec->par_x = NTSC_WIDE_PAR_X;
+ dvdec->par_y = NTSC_WIDE_PAR_Y;
+ } else {
+ dvdec->par_x = NTSC_NORMAL_PAR_X;
+ dvdec->par_y = NTSC_NORMAL_PAR_Y;
+ }
+ }
+ GST_DEBUG_OBJECT (dvdec, "Inferred PAR %d/%d from video format",
+ dvdec->par_x, dvdec->par_y);
+ }
+
+ /* ignoring rgb, bgr0 for now */
+ dvdec->bpp = 2;
+
+ othercaps = gst_caps_new_simple ("video/x-raw-yuv",
+ "format", GST_TYPE_FOURCC, GST_STR_FOURCC ("YUY2"),
+ "width", G_TYPE_INT, 720,
+ "height", G_TYPE_INT, dvdec->height,
+ "framerate", GST_TYPE_FRACTION, dvdec->framerate_numerator,
+ dvdec->framerate_denominator,
+ "pixel-aspect-ratio", GST_TYPE_FRACTION, dvdec->par_x,
+ dvdec->par_y, "interlaced", G_TYPE_BOOLEAN, dvdec->interlaced, NULL);
+
+ gst_pad_set_caps (dvdec->srcpad, othercaps);
+ gst_caps_unref (othercaps);
+
+ dvdec->src_negotiated = TRUE;
+
+ return TRUE;
+}
+
+static gboolean
+gst_dvdec_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstDVDec *dvdec;
+ gboolean res = TRUE;
+
+ dvdec = GST_DVDEC (gst_pad_get_parent (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ gst_segment_init (dvdec->segment, GST_FORMAT_UNDEFINED);
+ break;
+ case GST_EVENT_NEWSEGMENT:{
+ gboolean update;
+ gdouble rate, applied_rate;
+ GstFormat format;
+ gint64 start, stop, position;
+
+ gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
+ &format, &start, &stop, &position);
+
+ GST_DEBUG_OBJECT (dvdec, "Got NEWSEGMENT [%" GST_TIME_FORMAT
+ " - %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "]",
+ GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
+ GST_TIME_ARGS (position));
+
+ gst_segment_set_newsegment_full (dvdec->segment, update, rate,
+ applied_rate, format, start, stop, position);
+ break;
+ }
+ default:
+ break;
+ }
+
+ res = gst_pad_push_event (dvdec->srcpad, event);
+
+ return res;
+}
+
+static GstFlowReturn
+gst_dvdec_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstDVDec *dvdec;
+ guint8 *inframe;
+ guint8 *outframe;
+ guint8 *outframe_ptrs[3];
+ gint outframe_pitches[3];
+ GstBuffer *outbuf;
+ GstFlowReturn ret = GST_FLOW_OK;
+ guint length;
+ gint64 cstart, cstop;
+ gboolean PAL, wide;
+
+ dvdec = GST_DVDEC (gst_pad_get_parent (pad));
+ inframe = GST_BUFFER_DATA (buf);
+
+ /* buffer should be at least the size of one NTSC frame, this should
+ * be enough to decode the header. */
+ if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < NTSC_BUFFER))
+ goto wrong_size;
+
+ /* preliminary dropping. unref and return if outside of configured segment */
+ if ((dvdec->segment->format == GST_FORMAT_TIME) &&
+ (!(gst_segment_clip (dvdec->segment, GST_FORMAT_TIME,
+ GST_BUFFER_TIMESTAMP (buf),
+ GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf),
+ &cstart, &cstop))))
+ goto dropping;
+
+ if (G_UNLIKELY (dv_parse_header (dvdec->decoder, inframe) < 0))
+ goto parse_header_error;
+
+ /* get size */
+ PAL = dv_system_50_fields (dvdec->decoder);
+ wide = dv_format_wide (dvdec->decoder);
+
+ /* check the buffer is of right size after we know if we are
+ * dealing with PAL or NTSC */
+ length = (PAL ? PAL_BUFFER : NTSC_BUFFER);
+ if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < length))
+ goto wrong_size;
+
+ dv_parse_packs (dvdec->decoder, inframe);
+
+ if (dvdec->video_offset % dvdec->drop_factor != 0)
+ goto skip;
+
+ /* renegotiate on change */
+ if (PAL != dvdec->PAL || wide != dvdec->wide) {
+ dvdec->src_negotiated = FALSE;
+ dvdec->PAL = PAL;
+ dvdec->wide = wide;
+ }
+
+ dvdec->height = (dvdec->PAL ? PAL_HEIGHT : NTSC_HEIGHT);
+
+ dvdec->interlaced = !dv_is_progressive (dvdec->decoder);
+
+ /* negotiate if not done yet */
+ if (!dvdec->src_negotiated) {
+ if (!gst_dvdec_src_negotiate (dvdec))
+ goto not_negotiated;
+ }
+
+ ret =
+ gst_pad_alloc_buffer_and_set_caps (dvdec->srcpad, 0,
+ (720 * dvdec->height) * dvdec->bpp,
+ GST_PAD_CAPS (dvdec->srcpad), &outbuf);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto no_buffer;
+
+ outframe = GST_BUFFER_DATA (outbuf);
+
+ outframe_ptrs[0] = outframe;
+ outframe_pitches[0] = 720 * dvdec->bpp;
+
+ /* the rest only matters for YUY2 */
+ if (dvdec->bpp < 3) {
+ outframe_ptrs[1] = outframe_ptrs[0] + 720 * dvdec->height;
+ outframe_ptrs[2] = outframe_ptrs[1] + 360 * dvdec->height;
+
+ outframe_pitches[1] = dvdec->height / 2;
+ outframe_pitches[2] = outframe_pitches[1];
+ }
+
+ GST_DEBUG_OBJECT (dvdec, "decoding and pushing buffer");
+ dv_decode_full_frame (dvdec->decoder, inframe,
+ e_dv_color_yuv, outframe_ptrs, outframe_pitches);
+
+ GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_TFF);
+
+ GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf);
+ GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
+ GST_BUFFER_TIMESTAMP (outbuf) = cstart;
+ GST_BUFFER_DURATION (outbuf) = cstop - cstart;
+
+ ret = gst_pad_push (dvdec->srcpad, outbuf);
+
+skip:
+ dvdec->video_offset++;
+
+done:
+ gst_buffer_unref (buf);
+ gst_object_unref (dvdec);
+
+ return ret;
+
+ /* ERRORS */
+wrong_size:
+ {
+ GST_ELEMENT_ERROR (dvdec, STREAM, DECODE,
+ (NULL), ("Input buffer too small"));
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+parse_header_error:
+ {
+ GST_ELEMENT_ERROR (dvdec, STREAM, DECODE,
+ (NULL), ("Error parsing DV header"));
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+not_negotiated:
+ {
+ GST_DEBUG_OBJECT (dvdec, "could not negotiate output");
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ goto done;
+ }
+no_buffer:
+ {
+ GST_DEBUG_OBJECT (dvdec, "could not allocate buffer");
+ goto done;
+ }
+
+dropping:
+ {
+ GST_DEBUG_OBJECT (dvdec,
+ "dropping buffer since it's out of the configured segment");
+ goto done;
+ }
+}
+
+static GstStateChangeReturn
+gst_dvdec_change_state (GstElement * element, GstStateChange transition)
+{
+ GstDVDec *dvdec = GST_DVDEC (element);
+ GstStateChangeReturn ret;
+
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ dvdec->decoder =
+ dv_decoder_new (0, dvdec->clamp_luma, dvdec->clamp_chroma);
+ dvdec->decoder->quality = qualities[dvdec->quality];
+ dv_set_error_log (dvdec->decoder, NULL);
+ gst_segment_init (dvdec->segment, GST_FORMAT_UNDEFINED);
+ dvdec->src_negotiated = FALSE;
+ dvdec->sink_negotiated = FALSE;
+ /*
+ * Enable this function call when libdv2 0.100 or higher is more
+ * common
+ */
+ /* dv_set_quality (dvdec->decoder, qualities [dvdec->quality]); */
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ default:
+ break;
+ }
+
+ ret = parent_class->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ dv_decoder_free (dvdec->decoder);
+ dvdec->decoder = NULL;
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static void
+gst_dvdec_set_property (GObject * object, guint prop_id, const GValue * value,
+ GParamSpec * pspec)
+{
+ GstDVDec *dvdec = GST_DVDEC (object);
+
+ switch (prop_id) {
+ case PROP_CLAMP_LUMA:
+ dvdec->clamp_luma = g_value_get_boolean (value);
+ break;
+ case PROP_CLAMP_CHROMA:
+ dvdec->clamp_chroma = g_value_get_boolean (value);
+ break;
+ case PROP_QUALITY:
+ dvdec->quality = g_value_get_enum (value);
+ if ((dvdec->quality < 0) || (dvdec->quality > 5))
+ dvdec->quality = 0;
+ break;
+ case PROP_DECODE_NTH:
+ dvdec->drop_factor = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_dvdec_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstDVDec *dvdec = GST_DVDEC (object);
+
+ switch (prop_id) {
+ case PROP_CLAMP_LUMA:
+ g_value_set_boolean (value, dvdec->clamp_luma);
+ break;
+ case PROP_CLAMP_CHROMA:
+ g_value_set_boolean (value, dvdec->clamp_chroma);
+ break;
+ case PROP_QUALITY:
+ g_value_set_enum (value, dvdec->quality);
+ break;
+ case PROP_DECODE_NTH:
+ g_value_set_int (value, dvdec->drop_factor);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
diff --git a/ext/dv/gstdvdec.h b/ext/dv/gstdvdec.h
new file mode 100644
index 0000000..de8481d
--- /dev/null
+++ b/ext/dv/gstdvdec.h
@@ -0,0 +1,95 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_DVDEC_H__
+#define __GST_DVDEC_H__
+
+
+#include <gst/gst.h>
+#include <libdv/dv.h>
+
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_DVDEC \
+ (gst_dvdec_get_type())
+#define GST_DVDEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DVDEC,GstDVDec))
+#define GST_DVDEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DVDEC,GstDVDecClass))
+#define GST_IS_DVDEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DVDEC))
+#define GST_IS_DVDEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DVDEC))
+
+
+typedef struct _GstDVDec GstDVDec;
+typedef struct _GstDVDecClass GstDVDecClass;
+
+
+struct _GstDVDec {
+ GstElement element;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ dv_decoder_t *decoder;
+ gboolean clamp_luma;
+ gboolean clamp_chroma;
+ gint quality;
+
+ gboolean PAL;
+ gboolean interlaced;
+ gboolean wide;
+ gint frame_len;
+
+ /* input caps */
+ gboolean sink_negotiated;
+ gint framerate_numerator;
+ gint framerate_denominator;
+ gint height;
+ gint par_x;
+ gint par_y;
+ gboolean need_par;
+
+ /* negotiated output */
+ dv_color_space_t space;
+ gint bpp;
+ gboolean src_negotiated;
+
+ gint video_offset;
+ gint drop_factor;
+
+ GstSegment *segment;
+};
+
+struct _GstDVDecClass {
+ GstElementClass parent_class;
+};
+
+
+GType gst_dvdec_get_type (void);
+
+
+G_END_DECLS
+
+
+#endif /* __GST_DVDEC_H__ */
diff --git a/ext/dv/gstdvdemux.c b/ext/dv/gstdvdemux.c
new file mode 100644
index 0000000..467ebe5
--- /dev/null
+++ b/ext/dv/gstdvdemux.c
@@ -0,0 +1,1908 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * <2005> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <string.h>
+#include <math.h>
+
+#include <gst/audio/audio.h>
+#include "gstdvdemux.h"
+#include "gstsmptetimecode.h"
+
+/**
+ * SECTION:element-dvdemux
+ *
+ * dvdemux splits raw DV into its audio and video components. The audio will be
+ * decoded raw samples and the video will be encoded DV video.
+ *
+ * This element can operate in both push and pull mode depending on the
+ * capabilities of the upstream peer.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch filesrc location=test.dv ! dvdemux name=demux ! queue ! audioconvert ! alsasink demux. ! queue ! dvdec ! xvimagesink
+ * ]| This pipeline decodes and renders the raw DV stream to an audio and a videosink.
+ * </refsect2>
+ *
+ * Last reviewed on 2006-02-27 (0.10.3)
+ */
+
+/* DV output has two modes, normal and wide. The resolution is the same in both
+ * cases: 720 pixels wide by 576 pixels tall in PAL format, and 720x480 for
+ * NTSC.
+ *
+ * Each of the modes has its own pixel aspect ratio, which is fixed in practice
+ * by ITU-R BT.601 (also known as "CCIR-601" or "Rec.601"). Or so claims a
+ * reference that I culled from the reliable "internet",
+ * http://www.mir.com/DMG/aspect.html. Normal PAL is 59/54 and normal NTSC is
+ * 10/11. Because the pixel resolution is the same for both cases, we can get
+ * the pixel aspect ratio for wide recordings by multiplying by the ratio of
+ * display aspect ratios, 16/9 (for wide) divided by 4/3 (for normal):
+ *
+ * Wide NTSC: 10/11 * (16/9)/(4/3) = 40/33
+ * Wide PAL: 59/54 * (16/9)/(4/3) = 118/81
+ *
+ * However, the pixel resolution coming out of a DV source does not combine with
+ * the standard pixel aspect ratios to give a proper display aspect ratio. An
+ * image 480 pixels tall, with a 4:3 display aspect ratio, will be 768 pixels
+ * wide. But, if we take the normal PAL aspect ratio of 59/54, and multiply it
+ * with the width of the DV image (720 pixels), we get 786.666..., which is
+ * nonintegral and too wide. The camera is not outputting a 4:3 image.
+ *
+ * If the video sink for this stream has fixed dimensions (such as for
+ * fullscreen playback, or for a java applet in a web page), you then have two
+ * choices. Either you show the whole image, but pad the image with black
+ * borders on the top and bottom (like watching a widescreen video on a 4:3
+ * device), or you crop the video to the proper ratio. Apparently the latter is
+ * the standard practice.
+ *
+ * For its part, GStreamer is concerned with accuracy and preservation of
+ * information. This element outputs the 720x576 or 720x480 video that it
+ * recieves, noting the proper aspect ratio. This should not be a problem for
+ * windowed applications, which can change size to fit the video. Applications
+ * with fixed size requirements should decide whether to crop or pad which
+ * an element such as videobox can do.
+ */
+
+#define NTSC_HEIGHT 480
+#define NTSC_BUFFER 120000
+#define NTSC_FRAMERATE_NUMERATOR 30000
+#define NTSC_FRAMERATE_DENOMINATOR 1001
+
+#define PAL_HEIGHT 576
+#define PAL_BUFFER 144000
+#define PAL_FRAMERATE_NUMERATOR 25
+#define PAL_FRAMERATE_DENOMINATOR 1
+
+#define PAL_NORMAL_PAR_X 59
+#define PAL_NORMAL_PAR_Y 54
+#define PAL_WIDE_PAR_X 118
+#define PAL_WIDE_PAR_Y 81
+
+#define NTSC_NORMAL_PAR_X 10
+#define NTSC_NORMAL_PAR_Y 11
+#define NTSC_WIDE_PAR_X 40
+#define NTSC_WIDE_PAR_Y 33
+
+GST_DEBUG_CATEGORY_STATIC (dvdemux_debug);
+#define GST_CAT_DEFAULT dvdemux_debug
+
+static GstStaticPadTemplate sink_temp = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-dv, systemstream = (boolean) true")
+ );
+
+static GstStaticPadTemplate video_src_temp = GST_STATIC_PAD_TEMPLATE ("video",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS ("video/x-dv, systemstream = (boolean) false")
+ );
+
+static GstStaticPadTemplate audio_src_temp = GST_STATIC_PAD_TEMPLATE ("audio",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS ("audio/x-raw-int, "
+ "depth = (int) 16, "
+ "width = (int) 16, "
+ "signed = (boolean) TRUE, "
+ "channels = (int) {2, 4}, "
+ "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", "
+ "rate = (int) { 32000, 44100, 48000 }")
+ );
+
+
+GST_BOILERPLATE (GstDVDemux, gst_dvdemux, GstElement, GST_TYPE_ELEMENT);
+
+static void gst_dvdemux_finalize (GObject * object);
+
+/* query functions */
+static const GstQueryType *gst_dvdemux_get_src_query_types (GstPad * pad);
+static gboolean gst_dvdemux_src_query (GstPad * pad, GstQuery * query);
+static const GstQueryType *gst_dvdemux_get_sink_query_types (GstPad * pad);
+static gboolean gst_dvdemux_sink_query (GstPad * pad, GstQuery * query);
+
+/* convert functions */
+static gboolean gst_dvdemux_sink_convert (GstDVDemux * demux,
+ GstFormat src_format, gint64 src_value, GstFormat * dest_format,
+ gint64 * dest_value);
+static gboolean gst_dvdemux_src_convert (GstDVDemux * demux, GstPad * pad,
+ GstFormat src_format, gint64 src_value, GstFormat * dest_format,
+ gint64 * dest_value);
+
+/* event functions */
+static gboolean gst_dvdemux_send_event (GstElement * element, GstEvent * event);
+static gboolean gst_dvdemux_handle_src_event (GstPad * pad, GstEvent * event);
+static gboolean gst_dvdemux_handle_sink_event (GstPad * pad, GstEvent * event);
+
+/* scheduling functions */
+static void gst_dvdemux_loop (GstPad * pad);
+static GstFlowReturn gst_dvdemux_flush (GstDVDemux * dvdemux);
+static GstFlowReturn gst_dvdemux_chain (GstPad * pad, GstBuffer * buffer);
+
+/* state change functions */
+static gboolean gst_dvdemux_sink_activate (GstPad * sinkpad);
+static gboolean gst_dvdemux_sink_activate_push (GstPad * sinkpad,
+ gboolean active);
+static gboolean gst_dvdemux_sink_activate_pull (GstPad * sinkpad,
+ gboolean active);
+static GstStateChangeReturn gst_dvdemux_change_state (GstElement * element,
+ GstStateChange transition);
+
+static void
+gst_dvdemux_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class, &sink_temp);
+ gst_element_class_add_static_pad_template (element_class,
+ &video_src_temp);
+ gst_element_class_add_static_pad_template (element_class,
+ &audio_src_temp);
+
+ gst_element_class_set_details_simple (element_class,
+ "DV system stream demuxer", "Codec/Demuxer",
+ "Uses libdv to separate DV audio from DV video (libdv.sourceforge.net)",
+ "Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim@fluendo.com>");
+
+ GST_DEBUG_CATEGORY_INIT (dvdemux_debug, "dvdemux", 0, "DV demuxer element");
+}
+
+static void
+gst_dvdemux_class_init (GstDVDemuxClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = gst_dvdemux_finalize;
+
+ gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_dvdemux_change_state);
+ gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_dvdemux_send_event);
+}
+
+static void
+gst_dvdemux_init (GstDVDemux * dvdemux, GstDVDemuxClass * g_class)
+{
+ gint i;
+
+ dvdemux->sinkpad = gst_pad_new_from_static_template (&sink_temp, "sink");
+ /* we can operate in pull and push mode so we install
+ * a custom activate function */
+ gst_pad_set_activate_function (dvdemux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_dvdemux_sink_activate));
+ /* the function to activate in push mode */
+ gst_pad_set_activatepush_function (dvdemux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_dvdemux_sink_activate_push));
+ /* the function to activate in pull mode */
+ gst_pad_set_activatepull_function (dvdemux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_dvdemux_sink_activate_pull));
+ /* for push mode, this is the chain function */
+ gst_pad_set_chain_function (dvdemux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_dvdemux_chain));
+ /* handling events (in push mode only) */
+ gst_pad_set_event_function (dvdemux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_dvdemux_handle_sink_event));
+ /* query functions */
+ gst_pad_set_query_function (dvdemux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_dvdemux_sink_query));
+ gst_pad_set_query_type_function (dvdemux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_dvdemux_get_sink_query_types));
+
+ /* now add the pad */
+ gst_element_add_pad (GST_ELEMENT (dvdemux), dvdemux->sinkpad);
+
+ dvdemux->adapter = gst_adapter_new ();
+
+ /* we need 4 temp buffers for audio decoding which are of a static
+ * size and which we can allocate here */
+ for (i = 0; i < 4; i++) {
+ dvdemux->audio_buffers[i] =
+ (gint16 *) g_malloc (DV_AUDIO_MAX_SAMPLES * sizeof (gint16));
+ }
+}
+
+static void
+gst_dvdemux_finalize (GObject * object)
+{
+ GstDVDemux *dvdemux;
+ gint i;
+
+ dvdemux = GST_DVDEMUX (object);
+
+ g_object_unref (dvdemux->adapter);
+
+ /* clean up temp audio buffers */
+ for (i = 0; i < 4; i++) {
+ g_free (dvdemux->audio_buffers[i]);
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* reset to default values before starting streaming */
+static void
+gst_dvdemux_reset (GstDVDemux * dvdemux)
+{
+ dvdemux->frame_offset = 0;
+ dvdemux->audio_offset = 0;
+ dvdemux->video_offset = 0;
+ dvdemux->framecount = 0;
+ g_atomic_int_set (&dvdemux->found_header, 0);
+ dvdemux->frame_len = -1;
+ dvdemux->need_segment = FALSE;
+ dvdemux->new_media = FALSE;
+ dvdemux->framerate_numerator = 0;
+ dvdemux->framerate_denominator = 0;
+ dvdemux->height = 0;
+ dvdemux->frequency = 0;
+ dvdemux->channels = 0;
+ dvdemux->wide = FALSE;
+ gst_segment_init (&dvdemux->byte_segment, GST_FORMAT_BYTES);
+ gst_segment_init (&dvdemux->time_segment, GST_FORMAT_TIME);
+}
+
+static GstPad *
+gst_dvdemux_add_pad (GstDVDemux * dvdemux, GstStaticPadTemplate * template)
+{
+ gboolean no_more_pads;
+ GstPad *pad;
+
+ pad = gst_pad_new_from_static_template (template, template->name_template);
+
+ gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_dvdemux_src_query));
+
+ gst_pad_set_query_type_function (pad,
+ GST_DEBUG_FUNCPTR (gst_dvdemux_get_src_query_types));
+ gst_pad_set_event_function (pad,
+ GST_DEBUG_FUNCPTR (gst_dvdemux_handle_src_event));
+ gst_pad_use_fixed_caps (pad);
+ gst_pad_set_active (pad, TRUE);
+ gst_element_add_pad (GST_ELEMENT (dvdemux), pad);
+
+ no_more_pads =
+ (dvdemux->videosrcpad != NULL && template == &audio_src_temp) ||
+ (dvdemux->audiosrcpad != NULL && template == &video_src_temp);
+
+ if (no_more_pads)
+ gst_element_no_more_pads (GST_ELEMENT (dvdemux));
+
+ gst_pad_push_event (pad, gst_event_new_new_segment (FALSE,
+ dvdemux->byte_segment.rate, GST_FORMAT_TIME,
+ dvdemux->time_segment.start, dvdemux->time_segment.stop,
+ dvdemux->time_segment.start));
+
+ if (no_more_pads) {
+ gst_element_found_tags (GST_ELEMENT (dvdemux),
+ gst_tag_list_new_full (GST_TAG_CONTAINER_FORMAT, "DV", NULL));
+ }
+
+ return pad;
+}
+
+static void
+gst_dvdemux_remove_pads (GstDVDemux * dvdemux)
+{
+ if (dvdemux->videosrcpad) {
+ gst_element_remove_pad (GST_ELEMENT (dvdemux), dvdemux->videosrcpad);
+ dvdemux->videosrcpad = NULL;
+ }
+ if (dvdemux->audiosrcpad) {
+ gst_element_remove_pad (GST_ELEMENT (dvdemux), dvdemux->audiosrcpad);
+ dvdemux->audiosrcpad = NULL;
+ }
+}
+
+static gboolean
+gst_dvdemux_src_convert (GstDVDemux * dvdemux, GstPad * pad,
+ GstFormat src_format, gint64 src_value, GstFormat * dest_format,
+ gint64 * dest_value)
+{
+ gboolean res = TRUE;
+
+ if (*dest_format == src_format || src_value == -1) {
+ *dest_value = src_value;
+ goto done;
+ }
+
+ if (dvdemux->frame_len <= 0)
+ goto error;
+
+ if (dvdemux->decoder == NULL)
+ goto error;
+
+ GST_INFO_OBJECT (pad,
+ "src_value:%" G_GINT64_FORMAT ", src_format:%d, dest_format:%d",
+ src_value, src_format, *dest_format);
+
+ switch (src_format) {
+ case GST_FORMAT_BYTES:
+ switch (*dest_format) {
+ case GST_FORMAT_DEFAULT:
+ if (pad == dvdemux->videosrcpad)
+ *dest_value = src_value / dvdemux->frame_len;
+ else if (pad == dvdemux->audiosrcpad)
+ *dest_value = src_value / (2 * dvdemux->channels);
+ break;
+ case GST_FORMAT_TIME:
+ *dest_format = GST_FORMAT_TIME;
+ if (pad == dvdemux->videosrcpad)
+ *dest_value = gst_util_uint64_scale (src_value,
+ GST_SECOND * dvdemux->framerate_denominator,
+ dvdemux->frame_len * dvdemux->framerate_numerator);
+ else if (pad == dvdemux->audiosrcpad)
+ *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
+ 2 * dvdemux->frequency * dvdemux->channels);
+ break;
+ default:
+ res = FALSE;
+ }
+ break;
+ case GST_FORMAT_TIME:
+ switch (*dest_format) {
+ case GST_FORMAT_BYTES:
+ if (pad == dvdemux->videosrcpad)
+ *dest_value = gst_util_uint64_scale (src_value,
+ dvdemux->frame_len * dvdemux->framerate_numerator,
+ dvdemux->framerate_denominator * GST_SECOND);
+ else if (pad == dvdemux->audiosrcpad)
+ *dest_value = gst_util_uint64_scale_int (src_value,
+ 2 * dvdemux->frequency * dvdemux->channels, GST_SECOND);
+ break;
+ case GST_FORMAT_DEFAULT:
+ if (pad == dvdemux->videosrcpad) {
+ if (src_value)
+ *dest_value = gst_util_uint64_scale (src_value,
+ dvdemux->framerate_numerator,
+ dvdemux->framerate_denominator * GST_SECOND);
+ else
+ *dest_value = 0;
+ } else if (pad == dvdemux->audiosrcpad) {
+ *dest_value = gst_util_uint64_scale (src_value,
+ dvdemux->frequency, GST_SECOND);
+ }
+ break;
+ default:
+ res = FALSE;
+ }
+ break;
+ case GST_FORMAT_DEFAULT:
+ switch (*dest_format) {
+ case GST_FORMAT_TIME:
+ if (pad == dvdemux->videosrcpad) {
+ *dest_value = gst_util_uint64_scale (src_value,
+ GST_SECOND * dvdemux->framerate_denominator,
+ dvdemux->framerate_numerator);
+ } else if (pad == dvdemux->audiosrcpad) {
+ if (src_value)
+ *dest_value = gst_util_uint64_scale (src_value,
+ GST_SECOND, dvdemux->frequency);
+ else
+ *dest_value = 0;
+ }
+ break;
+ case GST_FORMAT_BYTES:
+ if (pad == dvdemux->videosrcpad) {
+ *dest_value = src_value * dvdemux->frame_len;
+ } else if (pad == dvdemux->audiosrcpad) {
+ *dest_value = src_value * 2 * dvdemux->channels;
+ }
+ break;
+ default:
+ res = FALSE;
+ }
+ break;
+ default:
+ res = FALSE;
+ }
+
+done:
+ GST_INFO_OBJECT (pad,
+ "Result : dest_format:%d, dest_value:%" G_GINT64_FORMAT ", res:%d",
+ *dest_format, *dest_value, res);
+ return res;
+
+ /* ERRORS */
+error:
+ {
+ GST_INFO ("source conversion failed");
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_dvdemux_sink_convert (GstDVDemux * dvdemux, GstFormat src_format,
+ gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
+{
+ gboolean res = TRUE;
+
+ GST_DEBUG_OBJECT (dvdemux, "%d -> %d", src_format, *dest_format);
+ GST_INFO_OBJECT (dvdemux,
+ "src_value:%" G_GINT64_FORMAT ", src_format:%d, dest_format:%d",
+ src_value, src_format, *dest_format);
+
+ if (*dest_format == GST_FORMAT_DEFAULT)
+ *dest_format = GST_FORMAT_TIME;
+
+ if (*dest_format == src_format || src_value == -1) {
+ *dest_value = src_value;
+ goto done;
+ }
+
+ if (dvdemux->frame_len <= 0)
+ goto error;
+
+ switch (src_format) {
+ case GST_FORMAT_BYTES:
+ switch (*dest_format) {
+ case GST_FORMAT_TIME:
+ {
+ guint64 frame;
+
+ /* get frame number, rounds down so don't combine this
+ * line and the next line. */
+ frame = src_value / dvdemux->frame_len;
+
+ *dest_value = gst_util_uint64_scale (frame,
+ GST_SECOND * dvdemux->framerate_denominator,
+ dvdemux->framerate_numerator);
+ break;
+ }
+ default:
+ res = FALSE;
+ }
+ break;
+ case GST_FORMAT_TIME:
+ switch (*dest_format) {
+ case GST_FORMAT_BYTES:
+ {
+ guint64 frame;
+
+ /* calculate the frame */
+ frame =
+ gst_util_uint64_scale (src_value, dvdemux->framerate_numerator,
+ dvdemux->framerate_denominator * GST_SECOND);
+
+ /* calculate the offset from the rounded frame */
+ *dest_value = frame * dvdemux->frame_len;
+ break;
+ }
+ default:
+ res = FALSE;
+ }
+ break;
+ default:
+ res = FALSE;
+ }
+ GST_INFO_OBJECT (dvdemux,
+ "Result : dest_format:%d, dest_value:%" G_GINT64_FORMAT ", res:%d",
+ *dest_format, *dest_value, res);
+
+done:
+ return res;
+
+error:
+ {
+ GST_INFO_OBJECT (dvdemux, "sink conversion failed");
+ return FALSE;
+ }
+}
+
+static const GstQueryType *
+gst_dvdemux_get_src_query_types (GstPad * pad)
+{
+ static const GstQueryType src_query_types[] = {
+ GST_QUERY_POSITION,
+ GST_QUERY_DURATION,
+ GST_QUERY_CONVERT,
+ 0
+ };
+
+ return src_query_types;
+}
+
+static gboolean
+gst_dvdemux_src_query (GstPad * pad, GstQuery * query)
+{
+ gboolean res = TRUE;
+ GstDVDemux *dvdemux;
+
+ dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_POSITION:
+ {
+ GstFormat format;
+ gint64 cur;
+
+ /* get target format */
+ gst_query_parse_position (query, &format, NULL);
+
+ /* bring the position to the requested format. */
+ if (!(res = gst_dvdemux_src_convert (dvdemux, pad,
+ GST_FORMAT_TIME, dvdemux->time_segment.last_stop,
+ &format, &cur)))
+ goto error;
+ gst_query_set_position (query, format, cur);
+ break;
+ }
+ case GST_QUERY_DURATION:
+ {
+ GstFormat format;
+ GstFormat format2;
+ gint64 end;
+
+ /* First ask the peer in the original format */
+ if (!gst_pad_peer_query (dvdemux->sinkpad, query)) {
+ /* get target format */
+ gst_query_parse_duration (query, &format, NULL);
+
+ /* change query to bytes to perform on peer */
+ gst_query_set_duration (query, GST_FORMAT_BYTES, -1);
+
+ /* Now ask the peer in BYTES format and try to convert */
+ if (!gst_pad_peer_query (dvdemux->sinkpad, query)) {
+ goto error;
+ }
+
+ /* get peer total length */
+ gst_query_parse_duration (query, NULL, &end);
+
+ /* convert end to requested format */
+ if (end != -1) {
+ format2 = format;
+ if (!(res = gst_dvdemux_sink_convert (dvdemux,
+ GST_FORMAT_BYTES, end, &format2, &end))) {
+ goto error;
+ }
+ gst_query_set_duration (query, format, end);
+ }
+ }
+ break;
+ }
+ case GST_QUERY_CONVERT:
+ {
+ GstFormat src_fmt, dest_fmt;
+ gint64 src_val, dest_val;
+
+ gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+ if (!(res =
+ gst_dvdemux_src_convert (dvdemux, pad, src_fmt, src_val,
+ &dest_fmt, &dest_val)))
+ goto error;
+ gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+ break;
+ }
+ default:
+ res = gst_pad_query_default (pad, query);
+ break;
+ }
+ gst_object_unref (dvdemux);
+
+ return res;
+
+ /* ERRORS */
+error:
+ {
+ gst_object_unref (dvdemux);
+ GST_DEBUG ("error source query");
+ return FALSE;
+ }
+}
+
+static const GstQueryType *
+gst_dvdemux_get_sink_query_types (GstPad * pad)
+{
+ static const GstQueryType sink_query_types[] = {
+ GST_QUERY_CONVERT,
+ 0
+ };
+
+ return sink_query_types;
+}
+
+static gboolean
+gst_dvdemux_sink_query (GstPad * pad, GstQuery * query)
+{
+ gboolean res = TRUE;
+ GstDVDemux *dvdemux;
+
+ dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_CONVERT:
+ {
+ GstFormat src_fmt, dest_fmt;
+ gint64 src_val, dest_val;
+
+ gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+ if (!(res =
+ gst_dvdemux_sink_convert (dvdemux, src_fmt, src_val, &dest_fmt,
+ &dest_val)))
+ goto error;
+ gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+ break;
+ }
+ default:
+ res = gst_pad_query_default (pad, query);
+ break;
+ }
+ gst_object_unref (dvdemux);
+
+ return res;
+
+ /* ERRORS */
+error:
+ {
+ gst_object_unref (dvdemux);
+ GST_DEBUG ("error handling sink query");
+ return FALSE;
+ }
+}
+
+/* takes ownership of the event */
+static gboolean
+gst_dvdemux_push_event (GstDVDemux * dvdemux, GstEvent * event)
+{
+ gboolean res = FALSE;
+
+ if (dvdemux->videosrcpad) {
+ gst_event_ref (event);
+ res |= gst_pad_push_event (dvdemux->videosrcpad, event);
+ }
+
+ if (dvdemux->audiosrcpad)
+ res |= gst_pad_push_event (dvdemux->audiosrcpad, event);
+ else
+ gst_event_unref (event);
+
+ return res;
+}
+
+static gboolean
+gst_dvdemux_handle_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstDVDemux *dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
+ gboolean res = TRUE;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_START:
+ /* we are not blocking on anything exect the push() calls
+ * to the peer which will be unblocked by forwarding the
+ * event.*/
+ res = gst_dvdemux_push_event (dvdemux, event);
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ gst_adapter_clear (dvdemux->adapter);
+ GST_DEBUG ("cleared adapter");
+ gst_segment_init (&dvdemux->byte_segment, GST_FORMAT_BYTES);
+ gst_segment_init (&dvdemux->time_segment, GST_FORMAT_TIME);
+ res = gst_dvdemux_push_event (dvdemux, event);
+ break;
+ case GST_EVENT_NEWSEGMENT:
+ {
+ gboolean update;
+ gdouble rate;
+ GstFormat format;
+ gint64 start, stop, time;
+
+ /* parse byte start and stop positions */
+ gst_event_parse_new_segment (event, &update, &rate, &format,
+ &start, &stop, &time);
+
+ switch (format) {
+ case GST_FORMAT_BYTES:
+ gst_segment_set_newsegment (&dvdemux->byte_segment, update,
+ rate, format, start, stop, time);
+
+ /* the update can always be sent */
+ if (update) {
+ GstEvent *update;
+
+ update = gst_event_new_new_segment (TRUE,
+ dvdemux->time_segment.rate, dvdemux->time_segment.format,
+ dvdemux->time_segment.start, dvdemux->time_segment.last_stop,
+ dvdemux->time_segment.time);
+
+ gst_dvdemux_push_event (dvdemux, update);
+ } else {
+ /* and queue a SEGMENT before sending the next set of buffers, we
+ * cannot convert to time yet as we might not know the size of the
+ * frames, etc.. */
+ dvdemux->need_segment = TRUE;
+ }
+ gst_event_unref (event);
+ break;
+ case GST_FORMAT_TIME:
+ gst_segment_set_newsegment (&dvdemux->time_segment, update,
+ rate, format, start, stop, time);
+
+ /* and we can just forward this time event */
+ res = gst_dvdemux_push_event (dvdemux, event);
+ break;
+ default:
+ gst_event_unref (event);
+ /* cannot accept this format */
+ res = FALSE;
+ break;
+ }
+ break;
+ }
+ case GST_EVENT_EOS:
+ /* flush any pending data, should be nothing left. */
+ gst_dvdemux_flush (dvdemux);
+ /* forward event */
+ res = gst_dvdemux_push_event (dvdemux, event);
+ /* and clear the adapter */
+ gst_adapter_clear (dvdemux->adapter);
+ break;
+ default:
+ res = gst_dvdemux_push_event (dvdemux, event);
+ break;
+ }
+
+ gst_object_unref (dvdemux);
+
+ return res;
+}
+
+/* convert a pair of values on the given srcpad */
+static gboolean
+gst_dvdemux_convert_src_pair (GstDVDemux * dvdemux, GstPad * pad,
+ GstFormat src_format, gint64 src_start, gint64 src_stop,
+ GstFormat dst_format, gint64 * dst_start, gint64 * dst_stop)
+{
+ gboolean res;
+
+ GST_INFO ("starting conversion of start");
+ /* bring the format to time on srcpad. */
+ if (!(res = gst_dvdemux_src_convert (dvdemux, pad,
+ src_format, src_start, &dst_format, dst_start))) {
+ goto done;
+ }
+ GST_INFO ("Finished conversion of start: %" G_GINT64_FORMAT, *dst_start);
+
+ GST_INFO ("starting conversion of stop");
+ /* bring the format to time on srcpad. */
+ if (!(res = gst_dvdemux_src_convert (dvdemux, pad,
+ src_format, src_stop, &dst_format, dst_stop))) {
+ /* could not convert seek format to time offset */
+ goto done;
+ }
+ GST_INFO ("Finished conversion of stop: %" G_GINT64_FORMAT, *dst_stop);
+done:
+ return res;
+}
+
+/* convert a pair of values on the sinkpad */
+static gboolean
+gst_dvdemux_convert_sink_pair (GstDVDemux * dvdemux,
+ GstFormat src_format, gint64 src_start, gint64 src_stop,
+ GstFormat dst_format, gint64 * dst_start, gint64 * dst_stop)
+{
+ gboolean res;
+
+ GST_INFO ("starting conversion of start");
+ /* bring the format to time on srcpad. */
+ if (!(res = gst_dvdemux_sink_convert (dvdemux,
+ src_format, src_start, &dst_format, dst_start))) {
+ goto done;
+ }
+ GST_INFO ("Finished conversion of start: %" G_GINT64_FORMAT, *dst_start);
+
+ GST_INFO ("starting conversion of stop");
+ /* bring the format to time on srcpad. */
+ if (!(res = gst_dvdemux_sink_convert (dvdemux,
+ src_format, src_stop, &dst_format, dst_stop))) {
+ /* could not convert seek format to time offset */
+ goto done;
+ }
+ GST_INFO ("Finished conversion of stop: %" G_GINT64_FORMAT, *dst_stop);
+done:
+ return res;
+}
+
+/* convert a pair of values on the srcpad to a pair of
+ * values on the sinkpad
+ */
+static gboolean
+gst_dvdemux_convert_src_to_sink (GstDVDemux * dvdemux, GstPad * pad,
+ GstFormat src_format, gint64 src_start, gint64 src_stop,
+ GstFormat dst_format, gint64 * dst_start, gint64 * dst_stop)
+{
+ GstFormat conv;
+ gboolean res;
+
+ conv = GST_FORMAT_TIME;
+ /* convert to TIME intermediate format */
+ if (!(res = gst_dvdemux_convert_src_pair (dvdemux, pad,
+ src_format, src_start, src_stop, conv, dst_start, dst_stop))) {
+ /* could not convert format to time offset */
+ goto done;
+ }
+ /* convert to dst format on sinkpad */
+ if (!(res = gst_dvdemux_convert_sink_pair (dvdemux,
+ conv, *dst_start, *dst_stop, dst_format, dst_start, dst_stop))) {
+ /* could not convert format to time offset */
+ goto done;
+ }
+done:
+ return res;
+}
+
+#if 0
+static gboolean
+gst_dvdemux_convert_segment (GstDVDemux * dvdemux, GstSegment * src,
+ GstSegment * dest)
+{
+ dest->rate = src->rate;
+ dest->abs_rate = src->abs_rate;
+ dest->flags = src->flags;
+
+ return TRUE;
+}
+#endif
+
+/* handle seek in push base mode.
+ *
+ * Convert the time seek to a bytes seek and send it
+ * upstream
+ * Does not take ownership of the event.
+ */
+static gboolean
+gst_dvdemux_handle_push_seek (GstDVDemux * dvdemux, GstPad * pad,
+ GstEvent * event)
+{
+ gboolean res = FALSE;
+ gdouble rate;
+ GstSeekFlags flags;
+ GstFormat format;
+ GstSeekType cur_type, stop_type;
+ gint64 cur, stop;
+ gint64 start_position, end_position;
+ GstEvent *newevent;
+
+ gst_event_parse_seek (event, &rate, &format, &flags,
+ &cur_type, &cur, &stop_type, &stop);
+
+ /* First try if upstream can handle time based seeks */
+ if (format == GST_FORMAT_TIME)
+ res = gst_pad_push_event (dvdemux->sinkpad, gst_event_ref (event));
+
+ if (!res) {
+ /* we convert the start/stop on the srcpad to the byte format
+ * on the sinkpad and forward the event */
+ res = gst_dvdemux_convert_src_to_sink (dvdemux, pad,
+ format, cur, stop, GST_FORMAT_BYTES, &start_position, &end_position);
+ if (!res)
+ goto done;
+
+ /* now this is the updated seek event on bytes */
+ newevent = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
+ cur_type, start_position, stop_type, end_position);
+
+ res = gst_pad_push_event (dvdemux->sinkpad, newevent);
+ }
+done:
+ return res;
+}
+
+/* position ourselves to the configured segment, used in pull mode.
+ * The input segment is in TIME format. We convert the time values
+ * to bytes values into our byte_segment which we use to pull data from
+ * the sinkpad peer.
+ */
+static gboolean
+gst_dvdemux_do_seek (GstDVDemux * demux, GstSegment * segment)
+{
+ gboolean res;
+ GstFormat format;
+
+ /* position to value configured is last_stop, this will round down
+ * to the byte position where the frame containing the given
+ * timestamp can be found. */
+ format = GST_FORMAT_BYTES;
+ res = gst_dvdemux_sink_convert (demux,
+ segment->format, segment->last_stop,
+ &format, &demux->byte_segment.last_stop);
+ if (!res)
+ goto done;
+
+ /* update byte segment start */
+ gst_dvdemux_sink_convert (demux,
+ segment->format, segment->start, &format, &demux->byte_segment.start);
+
+ /* update byte segment stop */
+ gst_dvdemux_sink_convert (demux,
+ segment->format, segment->stop, &format, &demux->byte_segment.stop);
+
+ /* update byte segment time */
+ gst_dvdemux_sink_convert (demux,
+ segment->format, segment->time, &format, &demux->byte_segment.time);
+
+ /* calculate current frame number */
+ format = GST_FORMAT_DEFAULT;
+ gst_dvdemux_src_convert (demux, demux->videosrcpad,
+ segment->format, segment->start, &format, &demux->video_offset);
+
+ /* calculate current audio number */
+ format = GST_FORMAT_DEFAULT;
+ gst_dvdemux_src_convert (demux, demux->audiosrcpad,
+ segment->format, segment->start, &format, &demux->audio_offset);
+
+ /* every DV frame corresponts with one video frame */
+ demux->frame_offset = demux->video_offset;
+
+done:
+ return res;
+}
+
+/* handle seek in pull base mode.
+ *
+ * Does not take ownership of the event.
+ */
+static gboolean
+gst_dvdemux_handle_pull_seek (GstDVDemux * demux, GstPad * pad,
+ GstEvent * event)
+{
+ gboolean res;
+ gdouble rate;
+ GstFormat format;
+ GstSeekFlags flags;
+ GstSeekType cur_type, stop_type;
+ gint64 cur, stop;
+ gboolean flush;
+ gboolean update;
+ GstSegment seeksegment;
+
+ GST_DEBUG_OBJECT (demux, "doing seek");
+
+ /* first bring the event format to TIME, our native format
+ * to perform the seek on */
+ if (event) {
+ GstFormat conv;
+
+ gst_event_parse_seek (event, &rate, &format, &flags,
+ &cur_type, &cur, &stop_type, &stop);
+
+ /* can't seek backwards yet */
+ if (rate <= 0.0)
+ goto wrong_rate;
+
+ /* convert input format to TIME */
+ conv = GST_FORMAT_TIME;
+ if (!(gst_dvdemux_convert_src_pair (demux, pad,
+ format, cur, stop, conv, &cur, &stop)))
+ goto no_format;
+
+ format = GST_FORMAT_TIME;
+ } else {
+ flags = 0;
+ }
+
+ flush = flags & GST_SEEK_FLAG_FLUSH;
+
+ /* send flush start */
+ if (flush)
+ gst_dvdemux_push_event (demux, gst_event_new_flush_start ());
+ else
+ gst_pad_pause_task (demux->sinkpad);
+
+ /* grab streaming lock, this should eventually be possible, either
+ * because the task is paused or our streaming thread stopped
+ * because our peer is flushing. */
+ GST_PAD_STREAM_LOCK (demux->sinkpad);
+
+ /* make copy into temp structure, we can only update the main one
+ * when the subclass actually could to the seek. */
+ memcpy (&seeksegment, &demux->time_segment, sizeof (GstSegment));
+
+ /* now configure the seek segment */
+ if (event) {
+ gst_segment_set_seek (&seeksegment, rate, format, flags,
+ cur_type, cur, stop_type, stop, &update);
+ }
+
+ GST_DEBUG_OBJECT (demux, "segment configured from %" G_GINT64_FORMAT
+ " to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
+ seeksegment.start, seeksegment.stop, seeksegment.last_stop);
+
+ /* do the seek, segment.last_stop contains new position. */
+ res = gst_dvdemux_do_seek (demux, &seeksegment);
+
+ /* and prepare to continue streaming */
+ if (flush) {
+ /* send flush stop, peer will accept data and events again. We
+ * are not yet providing data as we still have the STREAM_LOCK. */
+ gst_dvdemux_push_event (demux, gst_event_new_flush_stop ());
+ } else if (res && demux->running) {
+ /* we are running the current segment and doing a non-flushing seek,
+ * close the segment first based on the last_stop. */
+ GST_DEBUG_OBJECT (demux, "closing running segment %" G_GINT64_FORMAT
+ " to %" G_GINT64_FORMAT, demux->time_segment.start,
+ demux->time_segment.last_stop);
+
+ gst_dvdemux_push_event (demux,
+ gst_event_new_new_segment (TRUE,
+ demux->time_segment.rate, demux->time_segment.format,
+ demux->time_segment.start, demux->time_segment.last_stop,
+ demux->time_segment.time));
+ }
+
+ /* if successfull seek, we update our real segment and push
+ * out the new segment. */
+ if (res) {
+ memcpy (&demux->time_segment, &seeksegment, sizeof (GstSegment));
+
+ if (demux->time_segment.flags & GST_SEEK_FLAG_SEGMENT) {
+ gst_element_post_message (GST_ELEMENT_CAST (demux),
+ gst_message_new_segment_start (GST_OBJECT_CAST (demux),
+ demux->time_segment.format, demux->time_segment.last_stop));
+ }
+ if ((stop = demux->time_segment.stop) == -1)
+ stop = demux->time_segment.duration;
+
+ GST_INFO_OBJECT (demux,
+ "Saving newsegment event to be sent in streaming thread");
+
+ if (demux->pending_segment)
+ gst_event_unref (demux->pending_segment);
+
+ demux->pending_segment = gst_event_new_new_segment (FALSE,
+ demux->time_segment.rate, demux->time_segment.format,
+ demux->time_segment.last_stop, stop, demux->time_segment.time);
+
+ demux->need_segment = FALSE;
+ }
+
+ demux->running = TRUE;
+ /* and restart the task in case it got paused explicitely or by
+ * the FLUSH_START event we pushed out. */
+ gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_dvdemux_loop,
+ demux->sinkpad);
+
+ /* and release the lock again so we can continue streaming */
+ GST_PAD_STREAM_UNLOCK (demux->sinkpad);
+
+ return TRUE;
+
+ /* ERRORS */
+wrong_rate:
+ {
+ GST_DEBUG_OBJECT (demux, "negative playback rate %lf not supported.", rate);
+ return FALSE;
+ }
+no_format:
+ {
+ GST_DEBUG_OBJECT (demux, "cannot convert to TIME format, seek aborted.");
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_dvdemux_send_event (GstElement * element, GstEvent * event)
+{
+ GstDVDemux *dvdemux = GST_DVDEMUX (element);
+ gboolean res = FALSE;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ {
+ /* checking header and configuring the seek must be atomic */
+ GST_OBJECT_LOCK (dvdemux);
+ if (g_atomic_int_get (&dvdemux->found_header) == 0) {
+ GstEvent **event_p;
+
+ event_p = &dvdemux->seek_event;
+
+ /* We don't have pads yet. Keep the event. */
+ GST_INFO_OBJECT (dvdemux, "Keeping the seek event for later");
+
+ gst_event_replace (event_p, event);
+ GST_OBJECT_UNLOCK (dvdemux);
+
+ res = TRUE;
+ } else {
+ GST_OBJECT_UNLOCK (dvdemux);
+
+ if (dvdemux->seek_handler) {
+ res = dvdemux->seek_handler (dvdemux, dvdemux->videosrcpad, event);
+ gst_event_unref (event);
+ }
+ }
+ break;
+ }
+ default:
+ res = GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
+ break;
+ }
+
+ return res;
+}
+
+/* handle an event on the source pad, it's most likely a seek */
+static gboolean
+gst_dvdemux_handle_src_event (GstPad * pad, GstEvent * event)
+{
+ gboolean res = TRUE;
+ GstDVDemux *dvdemux;
+
+ dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ /* seek handler is installed based on scheduling mode */
+ if (dvdemux->seek_handler)
+ res = dvdemux->seek_handler (dvdemux, pad, event);
+ else
+ res = FALSE;
+ break;
+ case GST_EVENT_QOS:
+ /* we can't really (yet) do QoS */
+ res = FALSE;
+ break;
+ case GST_EVENT_NAVIGATION:
+ /* no navigation either... */
+ res = FALSE;
+ break;
+ default:
+ res = gst_pad_push_event (dvdemux->sinkpad, event);
+ event = NULL;
+ break;
+ }
+ if (event)
+ gst_event_unref (event);
+
+ gst_object_unref (dvdemux);
+
+ return res;
+}
+
+/* does not take ownership of buffer */
+static GstFlowReturn
+gst_dvdemux_demux_audio (GstDVDemux * dvdemux, GstBuffer * buffer,
+ guint64 duration)
+{
+ gint num_samples;
+ GstFlowReturn ret;
+ const guint8 *data;
+
+ data = GST_BUFFER_DATA (buffer);
+
+ dv_decode_full_audio (dvdemux->decoder, data, dvdemux->audio_buffers);
+
+ if (G_LIKELY ((num_samples = dv_get_num_samples (dvdemux->decoder)) > 0)) {
+ gint16 *a_ptr;
+ gint i, j;
+ GstBuffer *outbuf;
+ gint frequency, channels;
+
+ if (G_UNLIKELY (dvdemux->audiosrcpad == NULL))
+ dvdemux->audiosrcpad = gst_dvdemux_add_pad (dvdemux, &audio_src_temp);
+
+ /* get initial format or check if format changed */
+ frequency = dv_get_frequency (dvdemux->decoder);
+ channels = dv_get_num_channels (dvdemux->decoder);
+
+ if (G_UNLIKELY ((frequency != dvdemux->frequency)
+ || (channels != dvdemux->channels))) {
+ GstCaps *caps;
+
+ dvdemux->frequency = frequency;
+ dvdemux->channels = channels;
+
+ /* and set new caps */
+ caps = gst_caps_new_simple ("audio/x-raw-int",
+ "rate", G_TYPE_INT, frequency,
+ "depth", G_TYPE_INT, 16,
+ "width", G_TYPE_INT, 16,
+ "signed", G_TYPE_BOOLEAN, TRUE,
+ "channels", G_TYPE_INT, channels,
+ "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL);
+ gst_pad_set_caps (dvdemux->audiosrcpad, caps);
+ gst_caps_unref (caps);
+ }
+
+ outbuf = gst_buffer_new_and_alloc (num_samples *
+ sizeof (gint16) * dvdemux->channels);
+
+ a_ptr = (gint16 *) GST_BUFFER_DATA (outbuf);
+
+ for (i = 0; i < num_samples; i++) {
+ for (j = 0; j < dvdemux->channels; j++) {
+ *(a_ptr++) = dvdemux->audio_buffers[j][i];
+ }
+ }
+
+ GST_DEBUG ("pushing audio %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (dvdemux->time_segment.last_stop));
+
+ GST_BUFFER_TIMESTAMP (outbuf) = dvdemux->time_segment.last_stop;
+ GST_BUFFER_DURATION (outbuf) = duration;
+ GST_BUFFER_OFFSET (outbuf) = dvdemux->audio_offset;
+ dvdemux->audio_offset += num_samples;
+ GST_BUFFER_OFFSET_END (outbuf) = dvdemux->audio_offset;
+
+ if (dvdemux->new_media)
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (dvdemux->audiosrcpad));
+
+ ret = gst_pad_push (dvdemux->audiosrcpad, outbuf);
+ } else {
+ /* no samples */
+ ret = GST_FLOW_OK;
+ }
+
+ return ret;
+}
+
+/* takes ownership of buffer */
+static GstFlowReturn
+gst_dvdemux_demux_video (GstDVDemux * dvdemux, GstBuffer * buffer,
+ guint64 duration)
+{
+ GstBuffer *outbuf;
+ gint height;
+ gboolean wide;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ if (G_UNLIKELY (dvdemux->videosrcpad == NULL))
+ dvdemux->videosrcpad = gst_dvdemux_add_pad (dvdemux, &video_src_temp);
+
+ /* get params */
+ /* framerate is already up-to-date */
+ height = dvdemux->decoder->height;
+ wide = dv_format_wide (dvdemux->decoder);
+
+ /* see if anything changed */
+ if (G_UNLIKELY ((dvdemux->height != height) || dvdemux->wide != wide)) {
+ GstCaps *caps;
+ gint par_x, par_y;
+
+ dvdemux->height = height;
+ dvdemux->wide = wide;
+
+ if (dvdemux->decoder->system == e_dv_system_625_50) {
+ if (wide) {
+ par_x = PAL_WIDE_PAR_X;
+ par_y = PAL_WIDE_PAR_Y;
+ } else {
+ par_x = PAL_NORMAL_PAR_X;
+ par_y = PAL_NORMAL_PAR_Y;
+ }
+ } else {
+ if (wide) {
+ par_x = NTSC_WIDE_PAR_X;
+ par_y = NTSC_WIDE_PAR_Y;
+ } else {
+ par_x = NTSC_NORMAL_PAR_X;
+ par_y = NTSC_NORMAL_PAR_Y;
+ }
+ }
+
+ caps = gst_caps_new_simple ("video/x-dv",
+ "systemstream", G_TYPE_BOOLEAN, FALSE,
+ "width", G_TYPE_INT, 720,
+ "height", G_TYPE_INT, height,
+ "framerate", GST_TYPE_FRACTION, dvdemux->framerate_numerator,
+ dvdemux->framerate_denominator,
+ "pixel-aspect-ratio", GST_TYPE_FRACTION, par_x, par_y, NULL);
+ gst_pad_set_caps (dvdemux->videosrcpad, caps);
+ gst_caps_unref (caps);
+ }
+
+ /* takes ownership of buffer here, we just need to modify
+ * the metadata. */
+ outbuf = gst_buffer_make_metadata_writable (buffer);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = dvdemux->time_segment.last_stop;
+ GST_BUFFER_OFFSET (outbuf) = dvdemux->video_offset;
+ GST_BUFFER_OFFSET_END (outbuf) = dvdemux->video_offset + 1;
+ GST_BUFFER_DURATION (outbuf) = duration;
+
+ if (dvdemux->new_media)
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (dvdemux->videosrcpad));
+
+ GST_DEBUG ("pushing video %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (dvdemux->time_segment.last_stop));
+
+ ret = gst_pad_push (dvdemux->videosrcpad, outbuf);
+
+ dvdemux->video_offset++;
+
+ return ret;
+}
+
+static int
+get_ssyb_offset (int dif, int ssyb)
+{
+ int offset;
+
+ offset = dif * 12000; /* to dif */
+ offset += 80 * (1 + (ssyb / 6)); /* to subcode pack */
+ offset += 3; /* past header */
+ offset += 8 * (ssyb % 6); /* to ssyb */
+
+ return offset;
+}
+
+static gboolean
+gst_dvdemux_get_timecode (GstDVDemux * dvdemux, GstBuffer * buffer,
+ GstSMPTETimeCode * timecode)
+{
+ guint8 *data = GST_BUFFER_DATA (buffer);
+ int offset;
+ int dif;
+ int n_difs = dvdemux->decoder->num_dif_seqs;
+
+ for (dif = 0; dif < n_difs; dif++) {
+ offset = get_ssyb_offset (dif, 3);
+ if (data[offset + 3] == 0x13) {
+ timecode->frames = ((data[offset + 4] >> 4) & 0x3) * 10 +
+ (data[offset + 4] & 0xf);
+ timecode->seconds = ((data[offset + 5] >> 4) & 0x3) * 10 +
+ (data[offset + 5] & 0xf);
+ timecode->minutes = ((data[offset + 6] >> 4) & 0x3) * 10 +
+ (data[offset + 6] & 0xf);
+ timecode->hours = ((data[offset + 7] >> 4) & 0x3) * 10 +
+ (data[offset + 7] & 0xf);
+ GST_DEBUG ("got timecode %" GST_SMPTE_TIME_CODE_FORMAT,
+ GST_SMPTE_TIME_CODE_ARGS (timecode));
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gst_dvdemux_is_new_media (GstDVDemux * dvdemux, GstBuffer * buffer)
+{
+ guint8 *data = GST_BUFFER_DATA (buffer);
+ int aaux_offset;
+ int dif;
+ int n_difs;
+
+ n_difs = dvdemux->decoder->num_dif_seqs;
+
+ for (dif = 0; dif < n_difs; dif++) {
+ if (dif & 1) {
+ aaux_offset = (dif * 12000) + (6 + 16 * 1) * 80 + 3;
+ } else {
+ aaux_offset = (dif * 12000) + (6 + 16 * 4) * 80 + 3;
+ }
+ if (data[aaux_offset + 0] == 0x51) {
+ if ((data[aaux_offset + 2] & 0x80) == 0)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* takes ownership of buffer */
+static GstFlowReturn
+gst_dvdemux_demux_frame (GstDVDemux * dvdemux, GstBuffer * buffer)
+{
+ GstClockTime next_ts;
+ GstFlowReturn aret, vret, ret;
+ guint8 *data;
+ guint64 duration;
+ GstSMPTETimeCode timecode;
+ int frame_number;
+
+ if (G_UNLIKELY (dvdemux->need_segment)) {
+ GstEvent *event;
+ GstFormat format;
+
+ /* convert to time and store as start/end_timestamp */
+ format = GST_FORMAT_TIME;
+ if (!(gst_dvdemux_convert_sink_pair (dvdemux,
+ GST_FORMAT_BYTES, dvdemux->byte_segment.start,
+ dvdemux->byte_segment.stop, format,
+ &dvdemux->time_segment.start, &dvdemux->time_segment.stop)))
+ goto segment_error;
+
+ dvdemux->time_segment.rate = dvdemux->byte_segment.rate;
+ dvdemux->time_segment.abs_rate = dvdemux->byte_segment.abs_rate;
+ dvdemux->time_segment.last_stop = dvdemux->time_segment.start;
+
+ /* calculate current frame number */
+ format = GST_FORMAT_DEFAULT;
+ if (!(gst_dvdemux_src_convert (dvdemux, dvdemux->videosrcpad,
+ GST_FORMAT_TIME, dvdemux->time_segment.start,
+ &format, &dvdemux->frame_offset)))
+ goto segment_error;
+
+ GST_DEBUG_OBJECT (dvdemux, "sending segment start: %" GST_TIME_FORMAT
+ ", stop: %" GST_TIME_FORMAT ", time: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (dvdemux->time_segment.start),
+ GST_TIME_ARGS (dvdemux->time_segment.stop),
+ GST_TIME_ARGS (dvdemux->time_segment.start));
+
+ event = gst_event_new_new_segment (FALSE, dvdemux->byte_segment.rate,
+ GST_FORMAT_TIME, dvdemux->time_segment.start,
+ dvdemux->time_segment.stop, dvdemux->time_segment.start);
+ gst_dvdemux_push_event (dvdemux, event);
+
+ dvdemux->need_segment = FALSE;
+ }
+
+ gst_dvdemux_get_timecode (dvdemux, buffer, &timecode);
+ gst_smpte_time_code_get_frame_number (
+ (dvdemux->decoder->system == e_dv_system_625_50) ?
+ GST_SMPTE_TIME_CODE_SYSTEM_25 : GST_SMPTE_TIME_CODE_SYSTEM_30,
+ &frame_number, &timecode);
+
+ next_ts = gst_util_uint64_scale_int (
+ (dvdemux->frame_offset + 1) * GST_SECOND,
+ dvdemux->framerate_denominator, dvdemux->framerate_numerator);
+ duration = next_ts - dvdemux->time_segment.last_stop;
+
+ data = GST_BUFFER_DATA (buffer);
+
+ dv_parse_packs (dvdemux->decoder, data);
+ dvdemux->new_media = FALSE;
+ if (gst_dvdemux_is_new_media (dvdemux, buffer) &&
+ dvdemux->frames_since_new_media > 2) {
+ dvdemux->new_media = TRUE;
+ dvdemux->frames_since_new_media = 0;
+ }
+ dvdemux->frames_since_new_media++;
+
+ /* does not take ownership of buffer */
+ aret = ret = gst_dvdemux_demux_audio (dvdemux, buffer, duration);
+ if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)) {
+ gst_buffer_unref (buffer);
+ goto done;
+ }
+
+ /* takes ownership of buffer */
+ vret = ret = gst_dvdemux_demux_video (dvdemux, buffer, duration);
+ if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED))
+ goto done;
+
+ /* if both are not linked, we stop */
+ if (G_UNLIKELY (aret == GST_FLOW_NOT_LINKED && vret == GST_FLOW_NOT_LINKED)) {
+ ret = GST_FLOW_NOT_LINKED;
+ goto done;
+ }
+
+ gst_segment_set_last_stop (&dvdemux->time_segment, GST_FORMAT_TIME, next_ts);
+ dvdemux->frame_offset++;
+
+ /* check for the end of the segment */
+ if (dvdemux->time_segment.stop != -1 && next_ts > dvdemux->time_segment.stop)
+ ret = GST_FLOW_UNEXPECTED;
+ else
+ ret = GST_FLOW_OK;
+
+done:
+ return ret;
+
+ /* ERRORS */
+segment_error:
+ {
+ GST_DEBUG ("error generating new_segment event");
+ gst_buffer_unref (buffer);
+ return GST_FLOW_ERROR;
+ }
+}
+
+/* flush any remaining data in the adapter, used in chain based scheduling mode */
+static GstFlowReturn
+gst_dvdemux_flush (GstDVDemux * dvdemux)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ while (gst_adapter_available (dvdemux->adapter) >= dvdemux->frame_len) {
+ const guint8 *data;
+ gint length;
+
+ /* get the accumulated bytes */
+ data = gst_adapter_peek (dvdemux->adapter, dvdemux->frame_len);
+
+ /* parse header to know the length and other params */
+ if (G_UNLIKELY (dv_parse_header (dvdemux->decoder, data) < 0))
+ goto parse_header_error;
+
+ /* after parsing the header we know the length of the data */
+ length = dvdemux->frame_len = dvdemux->decoder->frame_size;
+ if (dvdemux->decoder->system == e_dv_system_625_50) {
+ dvdemux->framerate_numerator = PAL_FRAMERATE_NUMERATOR;
+ dvdemux->framerate_denominator = PAL_FRAMERATE_DENOMINATOR;
+ } else {
+ dvdemux->framerate_numerator = NTSC_FRAMERATE_NUMERATOR;
+ dvdemux->framerate_denominator = NTSC_FRAMERATE_DENOMINATOR;
+ }
+ g_atomic_int_set (&dvdemux->found_header, 1);
+
+ /* let demux_video set the height, it needs to detect when things change so
+ * it can reset caps */
+
+ /* if we still have enough for a frame, start decoding */
+ if (G_LIKELY (gst_adapter_available (dvdemux->adapter) >= length)) {
+ GstBuffer *buffer;
+
+ data = gst_adapter_take (dvdemux->adapter, length);
+
+ /* create buffer for the remainder of the code */
+ buffer = gst_buffer_new ();
+ GST_BUFFER_DATA (buffer) = (guint8 *) data;
+ GST_BUFFER_SIZE (buffer) = length;
+ GST_BUFFER_MALLOCDATA (buffer) = (guint8 *) data;
+
+ /* and decode the buffer, takes ownership */
+ ret = gst_dvdemux_demux_frame (dvdemux, buffer);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto done;
+ }
+ }
+done:
+ return ret;
+
+ /* ERRORS */
+parse_header_error:
+ {
+ GST_ELEMENT_ERROR (dvdemux, STREAM, DECODE,
+ (NULL), ("Error parsing DV header"));
+ return GST_FLOW_ERROR;
+ }
+}
+
+/* streaming operation:
+ *
+ * accumulate data until we have a frame, then decode.
+ */
+static GstFlowReturn
+gst_dvdemux_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstDVDemux *dvdemux;
+ GstFlowReturn ret;
+ GstClockTime timestamp;
+
+ dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
+
+ /* a discontinuity in the stream, we need to get rid of
+ * accumulated data in the adapter and assume a new frame
+ * starts after the discontinuity */
+ if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)))
+ gst_adapter_clear (dvdemux->adapter);
+
+ /* a timestamp always should be respected */
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+ gst_segment_set_last_stop (&dvdemux->time_segment, GST_FORMAT_TIME,
+ timestamp);
+ /* FIXME, adjust frame_offset and other counters */
+ }
+
+ gst_adapter_push (dvdemux->adapter, buffer);
+
+ /* Apparently dv_parse_header can read from the body of the frame
+ * too, so it needs more than header_size bytes. Wacky!
+ */
+ if (G_UNLIKELY (dvdemux->frame_len == -1)) {
+ /* if we don't know the length of a frame, we assume it is
+ * the NTSC_BUFFER length, as this is enough to figure out
+ * if this is PAL or NTSC */
+ dvdemux->frame_len = NTSC_BUFFER;
+ }
+
+ /* and try to flush pending frames */
+ ret = gst_dvdemux_flush (dvdemux);
+
+ gst_object_unref (dvdemux);
+
+ return ret;
+}
+
+/* pull based operation.
+ *
+ * Read header first to figure out the frame size. Then read
+ * and decode full frames.
+ */
+static void
+gst_dvdemux_loop (GstPad * pad)
+{
+ GstFlowReturn ret;
+ GstDVDemux *dvdemux;
+ GstBuffer *buffer = NULL;
+ const guint8 *data;
+
+ dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
+
+ if (G_UNLIKELY (g_atomic_int_get (&dvdemux->found_header) == 0)) {
+ GST_DEBUG_OBJECT (dvdemux, "pulling first buffer");
+ /* pull in NTSC sized buffer to figure out the frame
+ * length */
+ ret = gst_pad_pull_range (dvdemux->sinkpad,
+ dvdemux->byte_segment.last_stop, NTSC_BUFFER, &buffer);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto pause;
+
+ /* check buffer size, don't want to read small buffers */
+ if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < NTSC_BUFFER))
+ goto small_buffer;
+
+ data = GST_BUFFER_DATA (buffer);
+
+ /* parse header to know the length and other params */
+ if (G_UNLIKELY (dv_parse_header (dvdemux->decoder, data) < 0))
+ goto parse_header_error;
+
+ /* after parsing the header we know the length of the data */
+ dvdemux->frame_len = dvdemux->decoder->frame_size;
+ if (dvdemux->decoder->system == e_dv_system_625_50) {
+ dvdemux->framerate_numerator = PAL_FRAMERATE_NUMERATOR;
+ dvdemux->framerate_denominator = PAL_FRAMERATE_DENOMINATOR;
+ } else {
+ dvdemux->framerate_numerator = NTSC_FRAMERATE_NUMERATOR;
+ dvdemux->framerate_denominator = NTSC_FRAMERATE_DENOMINATOR;
+ }
+ dvdemux->need_segment = TRUE;
+
+ /* see if we need to read a larger part */
+ if (dvdemux->frame_len != NTSC_BUFFER) {
+ gst_buffer_unref (buffer);
+ buffer = NULL;
+ }
+
+ {
+ GstEvent *event;
+
+ /* setting header and prrforming the seek must be atomic */
+ GST_OBJECT_LOCK (dvdemux);
+ /* got header now */
+ g_atomic_int_set (&dvdemux->found_header, 1);
+
+ /* now perform pending seek if any. */
+ event = dvdemux->seek_event;
+ if (event)
+ gst_event_ref (event);
+ GST_OBJECT_UNLOCK (dvdemux);
+
+ if (event) {
+ if (!gst_dvdemux_handle_pull_seek (dvdemux, dvdemux->videosrcpad,
+ event)) {
+ GST_ELEMENT_WARNING (dvdemux, STREAM, DECODE, (NULL),
+ ("Error perfoming initial seek"));
+ }
+ gst_event_unref (event);
+
+ /* and we need to pull a new buffer in all cases. */
+ if (buffer) {
+ gst_buffer_unref (buffer);
+ buffer = NULL;
+ }
+ }
+ }
+ }
+
+
+ if (G_UNLIKELY (dvdemux->pending_segment)) {
+
+ /* now send the newsegment */
+ GST_DEBUG_OBJECT (dvdemux, "Sending newsegment from");
+
+ gst_dvdemux_push_event (dvdemux, dvdemux->pending_segment);
+ dvdemux->pending_segment = NULL;
+ }
+
+ if (G_LIKELY (buffer == NULL)) {
+ GST_DEBUG_OBJECT (dvdemux, "pulling buffer at offset %" G_GINT64_FORMAT,
+ dvdemux->byte_segment.last_stop);
+
+ ret = gst_pad_pull_range (dvdemux->sinkpad,
+ dvdemux->byte_segment.last_stop, dvdemux->frame_len, &buffer);
+ if (ret != GST_FLOW_OK)
+ goto pause;
+
+ /* check buffer size, don't want to read small buffers */
+ if (GST_BUFFER_SIZE (buffer) < dvdemux->frame_len)
+ goto small_buffer;
+ }
+ /* and decode the buffer */
+ ret = gst_dvdemux_demux_frame (dvdemux, buffer);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto pause;
+
+ /* and position ourselves for the next buffer */
+ dvdemux->byte_segment.last_stop += dvdemux->frame_len;
+
+done:
+ gst_object_unref (dvdemux);
+
+ return;
+
+ /* ERRORS */
+parse_header_error:
+ {
+ GST_ELEMENT_ERROR (dvdemux, STREAM, DECODE,
+ (NULL), ("Error parsing DV header"));
+ gst_buffer_unref (buffer);
+ dvdemux->running = FALSE;
+ gst_pad_pause_task (dvdemux->sinkpad);
+ gst_dvdemux_push_event (dvdemux, gst_event_new_eos ());
+ goto done;
+ }
+small_buffer:
+ {
+ GST_ELEMENT_ERROR (dvdemux, STREAM, DECODE,
+ (NULL), ("Error reading buffer"));
+ gst_buffer_unref (buffer);
+ dvdemux->running = FALSE;
+ gst_pad_pause_task (dvdemux->sinkpad);
+ gst_dvdemux_push_event (dvdemux, gst_event_new_eos ());
+ goto done;
+ }
+pause:
+ {
+ GST_INFO_OBJECT (dvdemux, "pausing task, %s", gst_flow_get_name (ret));
+ dvdemux->running = FALSE;
+ gst_pad_pause_task (dvdemux->sinkpad);
+ if (ret == GST_FLOW_UNEXPECTED) {
+ GST_LOG_OBJECT (dvdemux, "got eos");
+ /* perform EOS logic */
+ if (dvdemux->time_segment.flags & GST_SEEK_FLAG_SEGMENT) {
+ gst_element_post_message (GST_ELEMENT (dvdemux),
+ gst_message_new_segment_done (GST_OBJECT_CAST (dvdemux),
+ dvdemux->time_segment.format, dvdemux->time_segment.last_stop));
+ } else {
+ gst_dvdemux_push_event (dvdemux, gst_event_new_eos ());
+ }
+ } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
+ /* for fatal errors or not-linked we post an error message */
+ GST_ELEMENT_ERROR (dvdemux, STREAM, FAILED,
+ (NULL), ("streaming stopped, reason %s", gst_flow_get_name (ret)));
+ gst_dvdemux_push_event (dvdemux, gst_event_new_eos ());
+ }
+ goto done;
+ }
+}
+
+static gboolean
+gst_dvdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
+{
+ GstDVDemux *demux = GST_DVDEMUX (gst_pad_get_parent (sinkpad));
+
+ if (active) {
+ demux->seek_handler = gst_dvdemux_handle_push_seek;
+ } else {
+ demux->seek_handler = NULL;
+ }
+ gst_object_unref (demux);
+
+ return TRUE;
+}
+
+static gboolean
+gst_dvdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
+{
+ GstDVDemux *demux = GST_DVDEMUX (gst_pad_get_parent (sinkpad));
+
+ if (active) {
+ demux->running = TRUE;
+ demux->seek_handler = gst_dvdemux_handle_pull_seek;
+ gst_pad_start_task (sinkpad, (GstTaskFunction) gst_dvdemux_loop, sinkpad);
+ } else {
+ demux->seek_handler = NULL;
+ gst_pad_stop_task (sinkpad);
+ demux->running = FALSE;
+ }
+
+ gst_object_unref (demux);
+
+ return TRUE;
+};
+
+/* decide on push or pull based scheduling */
+static gboolean
+gst_dvdemux_sink_activate (GstPad * sinkpad)
+{
+ gboolean ret;
+
+ if (gst_pad_check_pull_range (sinkpad))
+ ret = gst_pad_activate_pull (sinkpad, TRUE);
+ else
+ ret = gst_pad_activate_push (sinkpad, TRUE);
+
+ return ret;
+};
+
+static GstStateChangeReturn
+gst_dvdemux_change_state (GstElement * element, GstStateChange transition)
+{
+ GstDVDemux *dvdemux = GST_DVDEMUX (element);
+ GstStateChangeReturn ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ dvdemux->decoder = dv_decoder_new (0, FALSE, FALSE);
+ dv_set_error_log (dvdemux->decoder, NULL);
+ gst_dvdemux_reset (dvdemux);
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ default:
+ break;
+ }
+
+ ret = parent_class->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_adapter_clear (dvdemux->adapter);
+ dv_decoder_free (dvdemux->decoder);
+ dvdemux->decoder = NULL;
+
+ gst_dvdemux_remove_pads (dvdemux);
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ {
+ GstEvent **event_p;
+
+ event_p = &dvdemux->seek_event;
+ gst_event_replace (event_p, NULL);
+ if (dvdemux->pending_segment)
+ gst_event_unref (dvdemux->pending_segment);
+ dvdemux->pending_segment = NULL;
+ break;
+ }
+ default:
+ break;
+ }
+ return ret;
+}
diff --git a/ext/dv/gstdvdemux.h b/ext/dv/gstdvdemux.h
new file mode 100644
index 0000000..9a4173d
--- /dev/null
+++ b/ext/dv/gstdvdemux.h
@@ -0,0 +1,98 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_DVDEMUX_H__
+#define __GST_DVDEMUX_H__
+
+#include <gst/gst.h>
+#include <libdv/dv.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DVDEMUX \
+ (gst_dvdemux_get_type())
+#define GST_DVDEMUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DVDEMUX,GstDVDemux))
+#define GST_DVDEMUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DVDEMUX,GstDVDemuxClass))
+#define GST_IS_DVDEMUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DVDEMUX))
+#define GST_IS_DVDEMUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DVDEMUX))
+
+
+typedef struct _GstDVDemux GstDVDemux;
+typedef struct _GstDVDemuxClass GstDVDemuxClass;
+
+typedef gboolean (*GstDVDemuxSeekHandler) (GstDVDemux *demux, GstPad * pad, GstEvent * event);
+
+
+struct _GstDVDemux {
+ GstElement element;
+
+ GstPad *sinkpad;
+ GstPad *videosrcpad;
+ GstPad *audiosrcpad;
+
+ dv_decoder_t *decoder;
+
+ GstAdapter *adapter;
+ gint frame_len;
+
+ /* video params */
+ gint framerate_numerator;
+ gint framerate_denominator;
+ gint height;
+ gboolean wide;
+ /* audio params */
+ gint frequency;
+ gint channels;
+
+ gint framecount;
+
+ gint64 frame_offset;
+ gint64 audio_offset;
+ gint64 video_offset;
+
+ GstDVDemuxSeekHandler seek_handler;
+ GstSegment byte_segment;
+ GstSegment time_segment;
+ gboolean running;
+ gboolean need_segment;
+ gboolean new_media;
+ int frames_since_new_media;
+
+ gint found_header; /* ATOMIC */
+ GstEvent *seek_event;
+ GstEvent *pending_segment;
+
+ gint16 *audio_buffers[4];
+};
+
+struct _GstDVDemuxClass {
+ GstElementClass parent_class;
+};
+
+GType gst_dvdemux_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_DVDEMUX_H__ */
diff --git a/ext/dv/gstsmptetimecode.c b/ext/dv/gstsmptetimecode.c
new file mode 100644
index 0000000..40a36d3
--- /dev/null
+++ b/ext/dv/gstsmptetimecode.c
@@ -0,0 +1,240 @@
+/* GStreamer
+ * Copyright (C) 2009 David A. Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Utility functions for handing SMPTE Time Codes, as described in
+ * SMPTE Standard 12M-1999.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstsmptetimecode.h"
+
+#define NTSC_FRAMES_PER_10_MINS (10*60*30 - 10*2 + 2)
+#define NTSC_FRAMES_PER_HOUR (6*NTSC_FRAMES_PER_10_MINS)
+
+/**
+ * gst_smpte_time_code_from_frame_number:
+ * @system: SMPTE Time Code system
+ * @time_code: pointer to time code structure
+ * @frame_number: integer frame number
+ *
+ * Converts a frame number to a time code.
+ *
+ * Returns: TRUE if the conversion was successful
+ */
+gboolean
+gst_smpte_time_code_from_frame_number (GstSMPTETimeCodeSystem system,
+ GstSMPTETimeCode * time_code, int frame_number)
+{
+ int ten_mins;
+ int n;
+
+ g_return_val_if_fail (time_code != NULL, FALSE);
+ g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), FALSE);
+
+ time_code->hours = 99;
+ time_code->minutes = 99;
+ time_code->seconds = 99;
+ time_code->frames = 99;
+
+ if (frame_number < 0)
+ return FALSE;
+
+ switch (system) {
+ case GST_SMPTE_TIME_CODE_SYSTEM_30:
+ if (frame_number >= 24 * NTSC_FRAMES_PER_HOUR)
+ return FALSE;
+
+ ten_mins = frame_number / NTSC_FRAMES_PER_10_MINS;
+ frame_number -= ten_mins * NTSC_FRAMES_PER_10_MINS;
+
+ time_code->hours = ten_mins / 6;
+ time_code->minutes = 10 * (ten_mins % 6);
+
+ if (frame_number < 2) {
+ /* treat the first two frames of each ten minutes specially */
+ time_code->seconds = 0;
+ time_code->frames = frame_number;
+ } else {
+ n = (frame_number - 2) / (60 * 30 - 2);
+ time_code->minutes += n;
+ frame_number -= n * (60 * 30 - 2);
+
+ time_code->seconds = frame_number / 30;
+ time_code->frames = frame_number % 30;
+ }
+ break;
+ case GST_SMPTE_TIME_CODE_SYSTEM_25:
+ if (frame_number >= 24 * 60 * 60 * 25)
+ return FALSE;
+
+ time_code->frames = frame_number % 25;
+ frame_number /= 25;
+ time_code->seconds = frame_number % 60;
+ frame_number /= 60;
+ time_code->minutes = frame_number % 60;
+ frame_number /= 60;
+ time_code->hours = frame_number;
+ break;
+ case GST_SMPTE_TIME_CODE_SYSTEM_24:
+ if (frame_number >= 24 * 60 * 60 * 24)
+ return FALSE;
+
+ time_code->frames = frame_number % 24;
+ frame_number /= 24;
+ time_code->seconds = frame_number % 60;
+ frame_number /= 60;
+ time_code->minutes = frame_number % 60;
+ frame_number /= 60;
+ time_code->hours = frame_number;
+ break;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_smpte_time_code_is_valid:
+ * @system: SMPTE Time Code system
+ * @time_code: pointer to time code structure
+ *
+ * Checks that the time code represents a valid time code.
+ *
+ * Returns: TRUE if the time code is valid
+ */
+gboolean
+gst_smpte_time_code_is_valid (GstSMPTETimeCodeSystem system,
+ GstSMPTETimeCode * time_code)
+{
+ g_return_val_if_fail (time_code != NULL, FALSE);
+ g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), FALSE);
+
+ if (time_code->hours < 0 || time_code->hours >= 24)
+ return FALSE;
+ if (time_code->minutes < 0 || time_code->minutes >= 60)
+ return FALSE;
+ if (time_code->seconds < 0 || time_code->seconds >= 60)
+ return FALSE;
+ if (time_code->frames < 0)
+ return FALSE;
+
+ switch (system) {
+ case GST_SMPTE_TIME_CODE_SYSTEM_30:
+ if (time_code->frames >= 30)
+ return FALSE;
+ if (time_code->frames >= 2 || time_code->seconds > 0)
+ return TRUE;
+ if (time_code->minutes % 10 != 0)
+ return FALSE;
+ break;
+ case GST_SMPTE_TIME_CODE_SYSTEM_25:
+ if (time_code->frames >= 25)
+ return FALSE;
+ break;
+ case GST_SMPTE_TIME_CODE_SYSTEM_24:
+ if (time_code->frames >= 24)
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+/**
+ * gst_smpte_time_get_frame_number:
+ * @system: SMPTE Time Code system
+ * @frame_number: pointer to frame number
+ * @time_code: pointer to time code structure
+ *
+ * Converts the time code structure to a linear frame number.
+ *
+ * Returns: TRUE if the time code could be converted
+ */
+gboolean
+gst_smpte_time_code_get_frame_number (GstSMPTETimeCodeSystem system,
+ int *frame_number, GstSMPTETimeCode * time_code)
+{
+ int frame = 0;
+
+ g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), FALSE);
+ g_return_val_if_fail (time_code != NULL, FALSE);
+
+ if (!gst_smpte_time_code_is_valid (system, time_code)) {
+ return FALSE;
+ }
+
+ switch (system) {
+ case GST_SMPTE_TIME_CODE_SYSTEM_30:
+ frame = time_code->hours * NTSC_FRAMES_PER_HOUR;
+ frame += (time_code->minutes / 10) * NTSC_FRAMES_PER_10_MINS;
+ frame += (time_code->minutes % 10) * (30 * 60 - 2);
+ frame += time_code->seconds * 30;
+ break;
+ case GST_SMPTE_TIME_CODE_SYSTEM_25:
+ time_code->frames =
+ 25 * ((time_code->hours * 60 + time_code->minutes) * 60 +
+ time_code->seconds);
+ break;
+ case GST_SMPTE_TIME_CODE_SYSTEM_24:
+ time_code->frames =
+ 24 * ((time_code->hours * 60 + time_code->minutes) * 60 +
+ time_code->seconds);
+ break;
+ }
+ frame += time_code->frames;
+
+ if (frame_number) {
+ *frame_number = frame;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_smpte_time_get_timestamp:
+ * @system: SMPTE Time Code system
+ * @time_code: pointer to time code structure
+ *
+ * Converts the time code structure to a timestamp.
+ *
+ * Returns: Time stamp for time code, or GST_CLOCK_TIME_NONE if time
+ * code is invalid.
+ */
+GstClockTime
+gst_smpte_time_code_get_timestamp (GstSMPTETimeCodeSystem system,
+ GstSMPTETimeCode * time_code)
+{
+ int frame_number;
+
+ g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system),
+ GST_CLOCK_TIME_NONE);
+ g_return_val_if_fail (time_code != NULL, GST_CLOCK_TIME_NONE);
+
+ if (gst_smpte_time_code_get_frame_number (system, &frame_number, time_code)) {
+ static int framerate_n[3] = { 3000, 25, 24 };
+ static int framerate_d[3] = { 1001, 1, 1 };
+
+ return gst_util_uint64_scale (frame_number,
+ GST_SECOND * framerate_d[system], framerate_n[system]);
+ }
+
+ return GST_CLOCK_TIME_NONE;
+}
diff --git a/ext/dv/gstsmptetimecode.h b/ext/dv/gstsmptetimecode.h
new file mode 100644
index 0000000..cdda03e
--- /dev/null
+++ b/ext/dv/gstsmptetimecode.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) 2009 David A. Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GST_SMPTE_TIME_CODE_H_
+#define _GST_SMPTE_TIME_CODE_H_
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstSMPTETimeCode GstSMPTETimeCode;
+
+/**
+ * GstSMPTETimeCode:
+ * @GST_SMPTE_TIME_CODE_SYSTEM_30: 29.97 frame per second system (NTSC)
+ * @GST_SMPTE_TIME_CODE_SYSTEM_25: 25 frame per second system (PAL)
+ * @GST_SMPTE_TIME_CODE_SYSTEM_24: 24 frame per second system
+ *
+ * Enum value representing SMPTE Time Code system.
+ */
+typedef enum {
+ GST_SMPTE_TIME_CODE_SYSTEM_30 = 0,
+ GST_SMPTE_TIME_CODE_SYSTEM_25,
+ GST_SMPTE_TIME_CODE_SYSTEM_24
+} GstSMPTETimeCodeSystem;
+
+struct _GstSMPTETimeCode {
+ int hours;
+ int minutes;
+ int seconds;
+ int frames;
+};
+
+#define GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID(x) \
+ ((x) >= GST_SMPTE_TIME_CODE_SYSTEM_30 && (x) <= GST_SMPTE_TIME_CODE_SYSTEM_24)
+
+#define GST_SMPTE_TIME_CODE_FORMAT "02d:%02d:%02d:%02d"
+#define GST_SMPTE_TIME_CODE_ARGS(timecode) \
+ (timecode)->hours, (timecode)->minutes, \
+ (timecode)->seconds, (timecode)->frames
+
+gboolean gst_smpte_time_code_is_valid (GstSMPTETimeCodeSystem system,
+ GstSMPTETimeCode *time_code);
+gboolean gst_smpte_time_code_from_frame_number (GstSMPTETimeCodeSystem system,
+ GstSMPTETimeCode *time_code, int frame_number);
+gboolean gst_smpte_time_code_get_frame_number (GstSMPTETimeCodeSystem system,
+ int *frame_number, GstSMPTETimeCode *time_code);
+GstClockTime gst_smpte_time_code_get_timestamp (GstSMPTETimeCodeSystem system,
+ GstSMPTETimeCode *time_code);
+
+G_END_DECLS
+
+#endif
+
diff --git a/ext/dv/smpte_test.c b/ext/dv/smpte_test.c
new file mode 100644
index 0000000..f18113c
--- /dev/null
+++ b/ext/dv/smpte_test.c
@@ -0,0 +1,81 @@
+
+#include "config.h"
+
+#include "gstsmptetimecode.h"
+
+#include <glib.h>
+
+#define NTSC_FRAMES_PER_10_MINS (10*60*30 - 10*2 + 2)
+#define NTSC_FRAMES_PER_HOUR (6*NTSC_FRAMES_PER_10_MINS)
+
+
+int
+main (int argc, char *argv[])
+{
+ GstSMPTETimeCode tc;
+ int i;
+ int min;
+
+ for (min = 0; min < 3; min++) {
+ g_print ("--- minute %d ---\n", min);
+ for (i = min * 60 * 30 - 5; i <= min * 60 * 30 + 5; i++) {
+ gst_smpte_time_code_from_frame_number (GST_SMPTE_TIME_CODE_SYSTEM_30, &tc,
+ i);
+ g_print ("%d %02d:%02d:%02d:%02d\n", i, tc.hours, tc.minutes, tc.seconds,
+ tc.frames);
+ }
+ }
+
+ for (min = 9; min < 12; min++) {
+ g_print ("--- minute %d ---\n", min);
+ for (i = min * 60 * 30 - 5 - 18; i <= min * 60 * 30 + 5 - 18; i++) {
+ gst_smpte_time_code_from_frame_number (GST_SMPTE_TIME_CODE_SYSTEM_30, &tc,
+ i);
+ g_print ("%d %02d:%02d:%02d:%02d\n", i, tc.hours, tc.minutes, tc.seconds,
+ tc.frames);
+ }
+ }
+
+ for (min = -1; min < 2; min++) {
+ int offset = NTSC_FRAMES_PER_HOUR;
+
+ g_print ("--- minute %d ---\n", min);
+ for (i = offset + min * 60 * 30 - 5; i <= offset + min * 60 * 30 + 5; i++) {
+ gst_smpte_time_code_from_frame_number (GST_SMPTE_TIME_CODE_SYSTEM_30, &tc,
+ i);
+ g_print ("%d %02d:%02d:%02d:%02d\n", i, tc.hours, tc.minutes, tc.seconds,
+ tc.frames);
+ }
+ }
+
+ for (min = 0; min < 1; min++) {
+ int offset = NTSC_FRAMES_PER_HOUR;
+
+ g_print ("--- minute %d ---\n", min);
+ for (i = 24 * offset - 5; i <= 24 * offset + 5; i++) {
+ gst_smpte_time_code_from_frame_number (GST_SMPTE_TIME_CODE_SYSTEM_30, &tc,
+ i);
+ g_print ("%d %02d:%02d:%02d:%02d\n", i, tc.hours, tc.minutes, tc.seconds,
+ tc.frames);
+ }
+ }
+
+ for (i = 0; i < 24 * NTSC_FRAMES_PER_HOUR; i++) {
+ int fn;
+ int ret;
+
+ gst_smpte_time_code_from_frame_number (GST_SMPTE_TIME_CODE_SYSTEM_30, &tc,
+ i);
+
+ ret = gst_smpte_time_code_get_frame_number (GST_SMPTE_TIME_CODE_SYSTEM_30,
+ &fn, &tc);
+ if (!ret) {
+ g_print ("bad valid at %d\n", i);
+ }
+ if (fn != i) {
+ g_print ("index mismatch %d != %d\n", fn, i);
+ }
+ }
+
+ return 0;
+}
diff --git a/ext/esd/Makefile.am b/ext/esd/Makefile.am
new file mode 100644
index 0000000..a7a1464
--- /dev/null
+++ b/ext/esd/Makefile.am
@@ -0,0 +1,14 @@
+plugin_LTLIBRARIES = libgstesd.la
+
+libgstesd_la_SOURCES = esdsink.c gstesd.c
+libgstesd_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(ESD_CFLAGS)
+libgstesd_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS) \
+ $(ESD_LIBS)
+libgstesd_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstesd_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = esdsink.h esdmon.h
+EXTRA_DIST =
diff --git a/ext/esd/Makefile.in b/ext/esd/Makefile.in
new file mode 100644
index 0000000..0d5be60
--- /dev/null
+++ b/ext/esd/Makefile.in
@@ -0,0 +1,821 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/esd
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstesd_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgstesd_la_OBJECTS = libgstesd_la-esdsink.lo \
+ libgstesd_la-gstesd.lo
+libgstesd_la_OBJECTS = $(am_libgstesd_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstesd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstesd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstesd_la_CFLAGS) $(CFLAGS) \
+ $(libgstesd_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstesd_la_SOURCES)
+DIST_SOURCES = $(libgstesd_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstesd.la
+libgstesd_la_SOURCES = esdsink.c gstesd.c
+libgstesd_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(ESD_CFLAGS)
+libgstesd_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS) \
+ $(ESD_LIBS)
+
+libgstesd_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstesd_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = esdsink.h esdmon.h
+EXTRA_DIST =
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/esd/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/esd/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstesd.la: $(libgstesd_la_OBJECTS) $(libgstesd_la_DEPENDENCIES) $(EXTRA_libgstesd_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstesd_la_LINK) -rpath $(plugindir) $(libgstesd_la_OBJECTS) $(libgstesd_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstesd_la-esdsink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstesd_la-gstesd.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstesd_la-esdsink.lo: esdsink.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstesd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstesd_la_CFLAGS) $(CFLAGS) -MT libgstesd_la-esdsink.lo -MD -MP -MF $(DEPDIR)/libgstesd_la-esdsink.Tpo -c -o libgstesd_la-esdsink.lo `test -f 'esdsink.c' || echo '$(srcdir)/'`esdsink.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstesd_la-esdsink.Tpo $(DEPDIR)/libgstesd_la-esdsink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='esdsink.c' object='libgstesd_la-esdsink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstesd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstesd_la_CFLAGS) $(CFLAGS) -c -o libgstesd_la-esdsink.lo `test -f 'esdsink.c' || echo '$(srcdir)/'`esdsink.c
+
+libgstesd_la-gstesd.lo: gstesd.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstesd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstesd_la_CFLAGS) $(CFLAGS) -MT libgstesd_la-gstesd.lo -MD -MP -MF $(DEPDIR)/libgstesd_la-gstesd.Tpo -c -o libgstesd_la-gstesd.lo `test -f 'gstesd.c' || echo '$(srcdir)/'`gstesd.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstesd_la-gstesd.Tpo $(DEPDIR)/libgstesd_la-gstesd.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstesd.c' object='libgstesd_la-gstesd.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstesd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstesd_la_CFLAGS) $(CFLAGS) -c -o libgstesd_la-gstesd.lo `test -f 'gstesd.c' || echo '$(srcdir)/'`gstesd.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/esd/esdmon.h b/ext/esd/esdmon.h
new file mode 100644
index 0000000..50fc7ee
--- /dev/null
+++ b/ext/esd/esdmon.h
@@ -0,0 +1,77 @@
+/* GStreamer
+ * Copyright (C) <2001,2002> Richard Boulton <richard-gst@tartarus.org>
+ *
+ * Based on example.c:
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_ESDMON_H__
+#define __GST_ESDMON_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ESDMON \
+ (gst_esdmon_get_type())
+#define GST_ESDMON(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ESDMON,GstEsdmon))
+#define GST_ESDMON_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ESDMON,GstEsdmonClass))
+#define GST_IS_ESDMON(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ESDMON))
+#define GST_IS_ESDMON_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ESDMON))
+
+typedef enum {
+ GST_ESDMON_OPEN = (GST_ELEMENT_FLAG_LAST << 0),
+ GST_ESDMON_FLAG_LAST = (GST_ELEMENT_FLAG_LAST << 2)
+} GstEsdSrcFlags;
+
+typedef struct _GstEsdmon GstEsdmon;
+typedef struct _GstEsdmonClass GstEsdmonClass;
+
+struct _GstEsdmon {
+ GstElement element;
+
+ GstPad *srcpad;
+
+ gchar* host;
+
+ int fd;
+
+ gint depth;
+ gint channels;
+ gint frequency;
+
+ guint64 basetime;
+ guint64 samples_since_basetime;
+ guint64 curoffset;
+ guint64 bytes_per_read;
+};
+
+struct _GstEsdmonClass {
+ GstElementClass parent_class;
+};
+
+GType gst_esdmon_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_ESDMON_H__ */
+
diff --git a/ext/esd/esdsink.c b/ext/esd/esdsink.c
new file mode 100644
index 0000000..6dfb364
--- /dev/null
+++ b/ext/esd/esdsink.c
@@ -0,0 +1,468 @@
+/* GStreamer
+ * Copyright (C) <2005> Arwed v. Merkatz <v.merkatz@gmx.net>
+ *
+ * Roughly based on the gstreamer 0.8 esdsink plugin:
+ * Copyright (C) <2001> Richard Boulton <richard-gst@tartarus.org>
+ *
+ * esdsink.c: an EsounD audio sink
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-esdsink
+ * @see_also: #GstAlsaSink, #GstAutoAudioSink
+ *
+ * This element outputs sound to an already-running Enlightened Sound Daemon
+ * (ESound Daemon, esd). Note that a sound daemon will never be auto-spawned
+ * through this element (regardless of the system configuration), since this
+ * is actively prevented by the element. If you must use esd, you need to
+ * make sure it is started automatically with your session or otherwise.
+ *
+ * TODO: insert some comments about how sucky esd is and that all the cool
+ * kids use pulseaudio or whatever these days.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch -v filesrc location=foo.ogg ! decodebin ! audioconvert ! audioresample ! esdsink
+ * ]| play an Ogg/Vorbis audio file via esd
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "esdsink.h"
+#include <esd.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <gst/gst-i18n-plugin.h>
+
+/* wtay: from my esd.h (debian unstable libesd0-dev 0.2.36-3) */
+#ifndef ESD_MAX_WRITE_SIZE
+#define ESD_MAX_WRITE_SIZE (21 * 4096)
+#endif
+
+GST_DEBUG_CATEGORY_EXTERN (esd_debug);
+#define GST_CAT_DEFAULT esd_debug
+
+enum
+{
+ PROP_0,
+ PROP_HOST
+};
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw-int, "
+ "endianness = (int) BYTE_ORDER, "
+ "signed = (boolean) TRUE, "
+ "width = (int) 16, "
+ "depth = (int) 16, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) [ 1, 2 ]; "
+ "audio/x-raw-int, "
+ "signed = (boolean) { true, false }, "
+ "width = (int) 8, "
+ "depth = (int) 8, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
+ );
+
+static void gst_esdsink_finalize (GObject * object);
+
+static GstCaps *gst_esdsink_getcaps (GstBaseSink * bsink);
+
+static gboolean gst_esdsink_open (GstAudioSink * asink);
+static gboolean gst_esdsink_close (GstAudioSink * asink);
+static gboolean gst_esdsink_prepare (GstAudioSink * asink,
+ GstRingBufferSpec * spec);
+static gboolean gst_esdsink_unprepare (GstAudioSink * asink);
+static guint gst_esdsink_write (GstAudioSink * asink, gpointer data,
+ guint length);
+static guint gst_esdsink_delay (GstAudioSink * asink);
+static void gst_esdsink_reset (GstAudioSink * asink);
+
+static void gst_esdsink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_esdsink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+GST_BOILERPLATE (GstEsdSink, gst_esdsink, GstAudioSink, GST_TYPE_AUDIO_SINK);
+
+static void
+gst_esdsink_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class, &sink_factory);
+ gst_element_class_set_details_simple (element_class, "Esound audio sink",
+ "Sink/Audio",
+ "Plays audio to an esound server",
+ "Arwed von Merkatz <v.merkatz@gmx.net>");
+}
+
+static void
+gst_esdsink_class_init (GstEsdSinkClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstBaseSinkClass *gstbasesink_class;
+ GstAudioSinkClass *gstaudiosink_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstbasesink_class = (GstBaseSinkClass *) klass;
+ gstaudiosink_class = (GstAudioSinkClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->finalize = gst_esdsink_finalize;
+
+ gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_esdsink_getcaps);
+
+ gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_esdsink_open);
+ gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_esdsink_close);
+ gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_esdsink_prepare);
+ gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_esdsink_unprepare);
+ gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_esdsink_write);
+ gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_esdsink_delay);
+ gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_esdsink_reset);
+
+ gobject_class->set_property = gst_esdsink_set_property;
+ gobject_class->get_property = gst_esdsink_get_property;
+
+ /* default value is filled in the _init method */
+ g_object_class_install_property (gobject_class, PROP_HOST,
+ g_param_spec_string ("host", "Host",
+ "The host running the esound daemon", NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_esdsink_init (GstEsdSink * esdsink, GstEsdSinkClass * klass)
+{
+ esdsink->fd = -1;
+ esdsink->ctrl_fd = -1;
+ esdsink->host = g_strdup (g_getenv ("ESPEAKER"));
+}
+
+static void
+gst_esdsink_finalize (GObject * object)
+{
+ GstEsdSink *esdsink = GST_ESDSINK (object);
+
+ gst_caps_replace (&esdsink->cur_caps, NULL);
+ g_free (esdsink->host);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_esdsink_getcaps (GstBaseSink * bsink)
+{
+ GstEsdSink *esdsink;
+
+ esdsink = GST_ESDSINK (bsink);
+
+ /* no fd, we're done with the template caps */
+ if (esdsink->ctrl_fd < 0 || esdsink->cur_caps == NULL) {
+ GST_LOG_OBJECT (esdsink, "getcaps called, returning template caps");
+ return NULL;
+ }
+
+ GST_LOG_OBJECT (esdsink, "returning %" GST_PTR_FORMAT, esdsink->cur_caps);
+
+ return gst_caps_ref (esdsink->cur_caps);
+}
+
+static gboolean
+gst_esdsink_open (GstAudioSink * asink)
+{
+ esd_server_info_t *server_info;
+ GstPadTemplate *pad_template;
+ GstEsdSink *esdsink;
+ gchar *saved_env;
+ gint i;
+
+ esdsink = GST_ESDSINK (asink);
+
+ GST_DEBUG_OBJECT (esdsink, "open");
+
+ /* ensure libesd doesn't auto-spawn a sound daemon if none is running yet */
+ saved_env = g_strdup (g_getenv ("ESD_NO_SPAWN"));
+ g_setenv ("ESD_NO_SPAWN", "1", TRUE);
+
+ /* now try to connect to any existing/running sound daemons */
+ esdsink->ctrl_fd = esd_open_sound (esdsink->host);
+
+ /* and restore the previous state */
+ if (saved_env != NULL) {
+ g_setenv ("ESD_NO_SPAWN", saved_env, TRUE);
+ } else {
+ g_unsetenv ("ESD_NO_SPAWN");
+ }
+ g_free (saved_env);
+
+ if (esdsink->ctrl_fd < 0)
+ goto couldnt_connect;
+
+ /* get server info */
+ server_info = esd_get_server_info (esdsink->ctrl_fd);
+ if (!server_info)
+ goto no_server_info;
+
+ GST_INFO_OBJECT (esdsink, "got server info rate: %i", server_info->rate);
+
+ pad_template = gst_static_pad_template_get (&sink_factory);
+ esdsink->cur_caps = gst_caps_copy (gst_pad_template_get_caps (pad_template));
+ gst_object_unref (pad_template);
+
+ for (i = 0; i < esdsink->cur_caps->structs->len; i++) {
+ GstStructure *s;
+
+ s = gst_caps_get_structure (esdsink->cur_caps, i);
+ gst_structure_set (s, "rate", G_TYPE_INT, server_info->rate, NULL);
+ }
+
+ esd_free_server_info (server_info);
+
+ GST_INFO_OBJECT (esdsink, "server caps: %" GST_PTR_FORMAT, esdsink->cur_caps);
+
+ return TRUE;
+
+ /* ERRORS */
+couldnt_connect:
+ {
+ GST_ELEMENT_ERROR (esdsink, RESOURCE, OPEN_WRITE,
+ (_("Could not establish connection to sound server")),
+ ("can't open connection to esound server"));
+ return FALSE;
+ }
+no_server_info:
+ {
+ GST_ELEMENT_ERROR (esdsink, RESOURCE, OPEN_WRITE,
+ (_("Failed to query sound server capabilities")),
+ ("couldn't get server info!"));
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_esdsink_close (GstAudioSink * asink)
+{
+ GstEsdSink *esdsink = GST_ESDSINK (asink);
+
+ GST_DEBUG_OBJECT (esdsink, "close");
+
+ gst_caps_replace (&esdsink->cur_caps, NULL);
+ esd_close (esdsink->ctrl_fd);
+ esdsink->ctrl_fd = -1;
+
+ return TRUE;
+}
+
+static gboolean
+gst_esdsink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
+{
+ GstEsdSink *esdsink = GST_ESDSINK (asink);
+ esd_format_t esdformat;
+
+ /* Name used by esound for this connection. */
+ const char connname[] = "GStreamer";
+
+ GST_DEBUG_OBJECT (esdsink, "prepare");
+
+ /* Bitmap describing audio format. */
+ esdformat = ESD_STREAM | ESD_PLAY;
+
+ switch (spec->depth) {
+ case 8:
+ esdformat |= ESD_BITS8;
+ break;
+ case 16:
+ esdformat |= ESD_BITS16;
+ break;
+ default:
+ goto unsupported_depth;
+ }
+
+ switch (spec->channels) {
+ case 1:
+ esdformat |= ESD_MONO;
+ break;
+ case 2:
+ esdformat |= ESD_STEREO;
+ break;
+ default:
+ goto unsupported_channels;
+ }
+
+ GST_INFO_OBJECT (esdsink,
+ "attempting to open data connection to esound server");
+
+ esdsink->fd =
+ esd_play_stream (esdformat, spec->rate, esdsink->host, connname);
+
+ if ((esdsink->fd < 0) || (esdsink->ctrl_fd < 0))
+ goto cannot_open;
+
+ esdsink->rate = spec->rate;
+
+ spec->segsize = ESD_BUF_SIZE;
+ spec->segtotal = (ESD_MAX_WRITE_SIZE / spec->segsize);
+
+ /* FIXME: this is wrong for signed ints (and the
+ * audioringbuffers should do it for us anyway) */
+ spec->silence_sample[0] = 0;
+ spec->silence_sample[1] = 0;
+ spec->silence_sample[2] = 0;
+ spec->silence_sample[3] = 0;
+
+ GST_INFO_OBJECT (esdsink, "successfully opened connection to esound server");
+
+ return TRUE;
+
+ /* ERRORS */
+unsupported_depth:
+ {
+ GST_ELEMENT_ERROR (esdsink, STREAM, WRONG_TYPE, (NULL),
+ ("can't handle sample depth of %d, only 8 or 16 supported",
+ spec->depth));
+ return FALSE;
+ }
+unsupported_channels:
+ {
+ GST_ELEMENT_ERROR (esdsink, STREAM, WRONG_TYPE, (NULL),
+ ("can't handle %d channels, only 1 or 2 supported", spec->channels));
+ return FALSE;
+ }
+cannot_open:
+ {
+ GST_ELEMENT_ERROR (esdsink, RESOURCE, OPEN_WRITE,
+ (_("Could not establish connection to sound server")),
+ ("can't open connection to esound server"));
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_esdsink_unprepare (GstAudioSink * asink)
+{
+ GstEsdSink *esdsink = GST_ESDSINK (asink);
+
+ if ((esdsink->fd < 0) && (esdsink->ctrl_fd < 0))
+ return TRUE;
+
+ close (esdsink->fd);
+ esdsink->fd = -1;
+
+ GST_INFO_OBJECT (esdsink, "closed sound device");
+
+ return TRUE;
+}
+
+
+static guint
+gst_esdsink_write (GstAudioSink * asink, gpointer data, guint length)
+{
+ GstEsdSink *esdsink = GST_ESDSINK (asink);
+ gint to_write = 0;
+
+ to_write = length;
+
+ while (to_write > 0) {
+ int done;
+
+ done = write (esdsink->fd, data, to_write);
+
+ if (done < 0)
+ goto write_error;
+
+ to_write -= done;
+ data = (char *) data + done;
+ }
+ return length;
+
+ /* ERRORS */
+write_error:
+ {
+ GST_ELEMENT_ERROR (esdsink, RESOURCE, WRITE,
+ ("Failed to write data to the esound daemon"), GST_ERROR_SYSTEM);
+ return -1;
+ }
+}
+
+static guint
+gst_esdsink_delay (GstAudioSink * asink)
+{
+ GstEsdSink *esdsink = GST_ESDSINK (asink);
+ guint latency;
+
+ latency = esd_get_latency (esdsink->ctrl_fd);
+
+ if (latency == (guint) - 1) {
+ GST_WARNING_OBJECT (asink, "couldn't get latency");
+ return 0;
+ }
+
+ /* latency is measured in samples at a rate of 44100, this
+ * cannot overflow. */
+ latency = latency * G_GINT64_CONSTANT (44100) / esdsink->rate;
+
+ GST_DEBUG_OBJECT (asink, "got latency: %u", latency);
+
+ return latency;
+}
+
+static void
+gst_esdsink_reset (GstAudioSink * asink)
+{
+ GST_DEBUG_OBJECT (asink, "reset called");
+}
+
+static void
+gst_esdsink_set_property (GObject * object, guint prop_id, const GValue * value,
+ GParamSpec * pspec)
+{
+ GstEsdSink *esdsink = GST_ESDSINK (object);
+
+ switch (prop_id) {
+ case PROP_HOST:
+ g_free (esdsink->host);
+ esdsink->host = g_value_dup_string (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_esdsink_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstEsdSink *esdsink = GST_ESDSINK (object);
+
+ switch (prop_id) {
+ case PROP_HOST:
+ g_value_set_string (value, esdsink->host);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
diff --git a/ext/esd/esdsink.h b/ext/esd/esdsink.h
new file mode 100644
index 0000000..2e69ea8
--- /dev/null
+++ b/ext/esd/esdsink.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2005> Arwed v. Merkatz <v.merkatz@gmx.net>
+ *
+ * esdsink.h: an EsounD audio sink
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_ESDSINK_H__
+#define __GST_ESDSINK_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosink.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ESDSINK \
+ (gst_esdsink_get_type())
+#define GST_ESDSINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ESDSINK,GstEsdSink))
+#define GST_ESDSINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ESDSINK,GstEsdSinkClass))
+#define GST_IS_ESDSINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ESDSINK))
+#define GST_IS_ESDSINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ESDSINK))
+
+typedef struct _GstEsdSink GstEsdSink;
+typedef struct _GstEsdSinkClass GstEsdSinkClass;
+
+struct _GstEsdSink {
+ GstAudioSink sink;
+
+ int fd;
+ int ctrl_fd;
+ gchar *host;
+
+ guint rate;
+ GstCaps *cur_caps;
+};
+
+struct _GstEsdSinkClass {
+ GstAudioSinkClass parent_class;
+};
+
+GType gst_esdsink_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_ESDSINK_H__ */
diff --git a/ext/esd/gstesd.c b/ext/esd/gstesd.c
new file mode 100644
index 0000000..dc65001
--- /dev/null
+++ b/ext/esd/gstesd.c
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "esdsink.h"
+#if 0
+#include "esdmon.h"
+#endif
+
+#include "gst/gst-i18n-plugin.h"
+
+GST_DEBUG_CATEGORY (esd_debug);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "esdsink", GST_RANK_MARGINAL,
+ GST_TYPE_ESDSINK))
+ return FALSE;
+
+#if 0
+ if (!gst_element_register (plugin, "esdmon", GST_RANK_NONE, GST_TYPE_ESDMON))
+ return FALSE;
+#endif
+
+ GST_DEBUG_CATEGORY_INIT (esd_debug, "esd", 0, "ESounD elements");
+
+#ifdef ENABLE_NLS
+ setlocale (LC_ALL, "");
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "esdsink",
+ "ESD Element Plugins",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/flac/Makefile.am b/ext/flac/Makefile.am
new file mode 100644
index 0000000..89805a3
--- /dev/null
+++ b/ext/flac/Makefile.am
@@ -0,0 +1,13 @@
+plugin_LTLIBRARIES = libgstflac.la
+
+libgstflac_la_SOURCES = gstflac.c gstflacdec.c gstflacenc.c gstflactag.c
+libgstflac_la_CFLAGS = -DGST_USE_UNSTABLE_API \
+ $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(FLAC_CFLAGS)
+libgstflac_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \
+ -lgstaudio-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) $(GST_LIBS) $(FLAC_LIBS)
+libgstflac_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstflac_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstflacenc.h gstflacdec.h gstflactag.h
diff --git a/ext/flac/Makefile.in b/ext/flac/Makefile.in
new file mode 100644
index 0000000..e02be9a
--- /dev/null
+++ b/ext/flac/Makefile.in
@@ -0,0 +1,838 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/flac
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstflac_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgstflac_la_OBJECTS = libgstflac_la-gstflac.lo \
+ libgstflac_la-gstflacdec.lo libgstflac_la-gstflacenc.lo \
+ libgstflac_la-gstflactag.lo
+libgstflac_la_OBJECTS = $(am_libgstflac_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstflac_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstflac_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstflac_la_CFLAGS) $(CFLAGS) \
+ $(libgstflac_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstflac_la_SOURCES)
+DIST_SOURCES = $(libgstflac_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstflac.la
+libgstflac_la_SOURCES = gstflac.c gstflacdec.c gstflacenc.c gstflactag.c
+libgstflac_la_CFLAGS = -DGST_USE_UNSTABLE_API \
+ $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(FLAC_CFLAGS)
+
+libgstflac_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \
+ -lgstaudio-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) $(GST_LIBS) $(FLAC_LIBS)
+
+libgstflac_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstflac_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = gstflacenc.h gstflacdec.h gstflactag.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/flac/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/flac/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstflac.la: $(libgstflac_la_OBJECTS) $(libgstflac_la_DEPENDENCIES) $(EXTRA_libgstflac_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstflac_la_LINK) -rpath $(plugindir) $(libgstflac_la_OBJECTS) $(libgstflac_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstflac_la-gstflac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstflac_la-gstflacdec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstflac_la-gstflacenc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstflac_la-gstflactag.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstflac_la-gstflac.lo: gstflac.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstflac_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstflac_la_CFLAGS) $(CFLAGS) -MT libgstflac_la-gstflac.lo -MD -MP -MF $(DEPDIR)/libgstflac_la-gstflac.Tpo -c -o libgstflac_la-gstflac.lo `test -f 'gstflac.c' || echo '$(srcdir)/'`gstflac.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstflac_la-gstflac.Tpo $(DEPDIR)/libgstflac_la-gstflac.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstflac.c' object='libgstflac_la-gstflac.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstflac_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstflac_la_CFLAGS) $(CFLAGS) -c -o libgstflac_la-gstflac.lo `test -f 'gstflac.c' || echo '$(srcdir)/'`gstflac.c
+
+libgstflac_la-gstflacdec.lo: gstflacdec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstflac_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstflac_la_CFLAGS) $(CFLAGS) -MT libgstflac_la-gstflacdec.lo -MD -MP -MF $(DEPDIR)/libgstflac_la-gstflacdec.Tpo -c -o libgstflac_la-gstflacdec.lo `test -f 'gstflacdec.c' || echo '$(srcdir)/'`gstflacdec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstflac_la-gstflacdec.Tpo $(DEPDIR)/libgstflac_la-gstflacdec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstflacdec.c' object='libgstflac_la-gstflacdec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstflac_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstflac_la_CFLAGS) $(CFLAGS) -c -o libgstflac_la-gstflacdec.lo `test -f 'gstflacdec.c' || echo '$(srcdir)/'`gstflacdec.c
+
+libgstflac_la-gstflacenc.lo: gstflacenc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstflac_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstflac_la_CFLAGS) $(CFLAGS) -MT libgstflac_la-gstflacenc.lo -MD -MP -MF $(DEPDIR)/libgstflac_la-gstflacenc.Tpo -c -o libgstflac_la-gstflacenc.lo `test -f 'gstflacenc.c' || echo '$(srcdir)/'`gstflacenc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstflac_la-gstflacenc.Tpo $(DEPDIR)/libgstflac_la-gstflacenc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstflacenc.c' object='libgstflac_la-gstflacenc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstflac_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstflac_la_CFLAGS) $(CFLAGS) -c -o libgstflac_la-gstflacenc.lo `test -f 'gstflacenc.c' || echo '$(srcdir)/'`gstflacenc.c
+
+libgstflac_la-gstflactag.lo: gstflactag.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstflac_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstflac_la_CFLAGS) $(CFLAGS) -MT libgstflac_la-gstflactag.lo -MD -MP -MF $(DEPDIR)/libgstflac_la-gstflactag.Tpo -c -o libgstflac_la-gstflactag.lo `test -f 'gstflactag.c' || echo '$(srcdir)/'`gstflactag.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstflac_la-gstflactag.Tpo $(DEPDIR)/libgstflac_la-gstflactag.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstflactag.c' object='libgstflac_la-gstflactag.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstflac_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstflac_la_CFLAGS) $(CFLAGS) -c -o libgstflac_la-gstflactag.lo `test -f 'gstflactag.c' || echo '$(srcdir)/'`gstflactag.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/flac/gstflac.c b/ext/flac/gstflac.c
new file mode 100644
index 0000000..e093e71
--- /dev/null
+++ b/ext/flac/gstflac.c
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstflacenc.h"
+#include "gstflacdec.h"
+#include "gstflactag.h"
+
+#include <gst/tag/tag.h>
+#include <gst/gst-i18n-plugin.h>
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+#ifdef ENABLE_NLS
+ GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+ LOCALEDIR);
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+ if (!gst_element_register (plugin, "flacenc", GST_RANK_PRIMARY,
+ GST_TYPE_FLAC_ENC))
+ return FALSE;
+ if (!gst_element_register (plugin, "flacdec", GST_RANK_PRIMARY,
+ GST_TYPE_FLAC_DEC))
+ return FALSE;
+ if (!gst_element_register (plugin, "flactag", GST_RANK_PRIMARY,
+ gst_flac_tag_get_type ()))
+ return FALSE;
+
+ gst_tag_register_musicbrainz_tags ();
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "flac",
+ "The FLAC Lossless compressor Codec",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c
new file mode 100644
index 0000000..10f8916
--- /dev/null
+++ b/ext/flac/gstflacdec.c
@@ -0,0 +1,2176 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) <2006> Jan Schmidt <thaytan at mad scientist com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-flacdec
+ * @see_also: #GstFlacEnc
+ *
+ * flacdec decodes FLAC streams.
+ * <ulink url="http://flac.sourceforge.net/">FLAC</ulink>
+ * is a Free Lossless Audio Codec.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch filesrc location=media/small/dark.441-16-s.flac ! flacdec ! audioconvert ! audioresample ! autoaudiosink
+ * ]|
+ * |[
+ * gst-launch gnomevfssrc location=http://gstreamer.freedesktop.org/media/small/dark.441-16-s.flac ! flacdec ! audioconvert ! audioresample ! queue min-threshold-buffers=10 ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+/* TODO: add seeking when operating chain-based with unframed input */
+/* FIXME: demote/remove granulepos handling and make more time-centric */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <string.h>
+
+#include "gstflacdec.h"
+#include <gst/gst-i18n-plugin.h>
+#include <gst/gsttagsetter.h>
+#include <gst/base/gsttypefindhelper.h>
+#include <gst/audio/multichannel.h>
+#include <gst/tag/tag.h>
+
+/* Taken from http://flac.sourceforge.net/format.html#frame_header */
+static const GstAudioChannelPosition channel_positions[8][8] = {
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_MONO},
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
+ /* FIXME: 7/8 channel layouts are not defined in the FLAC specs */
+ {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE,
+ GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
+};
+
+GST_DEBUG_CATEGORY_STATIC (flacdec_debug);
+#define GST_CAT_DEFAULT flacdec_debug
+
+static void gst_flac_dec_finalize (GObject * object);
+static void gst_flac_dec_loop (GstPad * pad);
+
+static GstStateChangeReturn gst_flac_dec_change_state (GstElement * element,
+ GstStateChange transition);
+static const GstQueryType *gst_flac_dec_get_src_query_types (GstPad * pad);
+static const GstQueryType *gst_flac_dec_get_sink_query_types (GstPad * pad);
+static gboolean gst_flac_dec_sink_query (GstPad * pad, GstQuery * query);
+static gboolean gst_flac_dec_src_query (GstPad * pad, GstQuery * query);
+static gboolean gst_flac_dec_convert_src (GstPad * pad, GstFormat src_format,
+ gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
+static gboolean gst_flac_dec_src_event (GstPad * pad, GstEvent * event);
+static gboolean gst_flac_dec_sink_activate (GstPad * sinkpad);
+static gboolean gst_flac_dec_sink_activate_pull (GstPad * sinkpad,
+ gboolean active);
+static gboolean gst_flac_dec_sink_activate_push (GstPad * sinkpad,
+ gboolean active);
+static gboolean gst_flac_dec_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_flac_dec_chain (GstPad * pad, GstBuffer * buf);
+
+static void gst_flac_dec_reset_decoders (GstFlacDec * flacdec);
+static void gst_flac_dec_setup_decoder (GstFlacDec * flacdec);
+
+static FLAC__StreamDecoderReadStatus
+gst_flac_dec_read_seekable (const FLAC__StreamDecoder * decoder,
+ FLAC__byte buffer[], size_t * bytes, void *client_data);
+static FLAC__StreamDecoderReadStatus
+gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder,
+ FLAC__byte buffer[], size_t * bytes, void *client_data);
+static FLAC__StreamDecoderSeekStatus
+gst_flac_dec_seek (const FLAC__StreamDecoder * decoder,
+ FLAC__uint64 position, void *client_data);
+static FLAC__StreamDecoderTellStatus
+gst_flac_dec_tell (const FLAC__StreamDecoder * decoder,
+ FLAC__uint64 * position, void *client_data);
+static FLAC__StreamDecoderLengthStatus
+gst_flac_dec_length (const FLAC__StreamDecoder * decoder,
+ FLAC__uint64 * length, void *client_data);
+static FLAC__bool gst_flac_dec_eof (const FLAC__StreamDecoder * decoder,
+ void *client_data);
+static FLAC__StreamDecoderWriteStatus
+gst_flac_dec_write_stream (const FLAC__StreamDecoder * decoder,
+ const FLAC__Frame * frame,
+ const FLAC__int32 * const buffer[], void *client_data);
+static void gst_flac_dec_metadata_cb (const FLAC__StreamDecoder *
+ decoder, const FLAC__StreamMetadata * metadata, void *client_data);
+static void gst_flac_dec_error_cb (const FLAC__StreamDecoder *
+ decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+GST_BOILERPLATE (GstFlacDec, gst_flac_dec, GstElement, GST_TYPE_ELEMENT);
+
+/* FIXME 0.11: Use width=32 for all depths and let audioconvert
+ * handle the conversions instead of doing it ourself.
+ */
+#define GST_FLAC_DEC_SRC_CAPS \
+ "audio/x-raw-int, " \
+ "endianness = (int) BYTE_ORDER, " \
+ "signed = (boolean) true, " \
+ "width = (int) { 8, 16, 32 }, " \
+ "depth = (int) [ 4, 32 ], " \
+ "rate = (int) [ 1, 655350 ], " \
+ "channels = (int) [ 1, 8 ]"
+
+static GstStaticPadTemplate flac_dec_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_FLAC_DEC_SRC_CAPS));
+static GstStaticPadTemplate flac_dec_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-flac")
+ );
+
+static void
+gst_flac_dec_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &flac_dec_src_factory);
+ gst_element_class_add_static_pad_template (element_class,
+ &flac_dec_sink_factory);
+ gst_element_class_set_details_simple (element_class, "FLAC audio decoder",
+ "Codec/Decoder/Audio",
+ "Decodes FLAC lossless audio streams", "Wim Taymans <wim@fluendo.com>");
+
+ GST_DEBUG_CATEGORY_INIT (flacdec_debug, "flacdec", 0, "flac decoder");
+}
+
+static void
+gst_flac_dec_class_init (GstFlacDecClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GObjectClass *gobject_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gobject_class = (GObjectClass *) klass;
+
+ gobject_class->finalize = gst_flac_dec_finalize;
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_flac_dec_change_state);
+}
+
+static void
+gst_flac_dec_init (GstFlacDec * flacdec, GstFlacDecClass * klass)
+{
+ flacdec->sinkpad =
+ gst_pad_new_from_static_template (&flac_dec_sink_factory, "sink");
+ gst_pad_set_activate_function (flacdec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_flac_dec_sink_activate));
+ gst_pad_set_activatepull_function (flacdec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_flac_dec_sink_activate_pull));
+ gst_pad_set_activatepush_function (flacdec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_flac_dec_sink_activate_push));
+ gst_pad_set_query_type_function (flacdec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_flac_dec_get_sink_query_types));
+ gst_pad_set_query_function (flacdec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_flac_dec_sink_query));
+ gst_pad_set_event_function (flacdec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_flac_dec_sink_event));
+ gst_pad_set_chain_function (flacdec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_flac_dec_chain));
+ gst_element_add_pad (GST_ELEMENT (flacdec), flacdec->sinkpad);
+
+ flacdec->srcpad =
+ gst_pad_new_from_static_template (&flac_dec_src_factory, "src");
+ gst_pad_set_query_type_function (flacdec->srcpad,
+ GST_DEBUG_FUNCPTR (gst_flac_dec_get_src_query_types));
+ gst_pad_set_query_function (flacdec->srcpad,
+ GST_DEBUG_FUNCPTR (gst_flac_dec_src_query));
+ gst_pad_set_event_function (flacdec->srcpad,
+ GST_DEBUG_FUNCPTR (gst_flac_dec_src_event));
+ gst_pad_use_fixed_caps (flacdec->srcpad);
+ gst_element_add_pad (GST_ELEMENT (flacdec), flacdec->srcpad);
+
+ gst_flac_dec_reset_decoders (flacdec);
+}
+
+static void
+gst_flac_dec_reset_decoders (GstFlacDec * flacdec)
+{
+ /* Clean up the decoder */
+ if (flacdec->decoder) {
+ FLAC__stream_decoder_delete (flacdec->decoder);
+ flacdec->decoder = NULL;
+ }
+
+ if (flacdec->adapter) {
+ gst_adapter_clear (flacdec->adapter);
+ g_object_unref (flacdec->adapter);
+ flacdec->adapter = NULL;
+ }
+
+ if (flacdec->close_segment) {
+ gst_event_unref (flacdec->close_segment);
+ flacdec->close_segment = NULL;
+ }
+ if (flacdec->start_segment) {
+ gst_event_unref (flacdec->start_segment);
+ flacdec->start_segment = NULL;
+ }
+ if (flacdec->tags) {
+ gst_tag_list_free (flacdec->tags);
+ flacdec->tags = NULL;
+ }
+ if (flacdec->pending) {
+ gst_buffer_unref (flacdec->pending);
+ flacdec->pending = NULL;
+ }
+
+ flacdec->segment.last_stop = 0;
+ flacdec->offset = 0;
+ flacdec->init = TRUE;
+}
+
+static void
+gst_flac_dec_setup_decoder (GstFlacDec * dec)
+{
+ gst_flac_dec_reset_decoders (dec);
+
+ dec->tags = gst_tag_list_new ();
+ gst_tag_list_add (dec->tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_AUDIO_CODEC, "FLAC", NULL);
+
+ dec->adapter = gst_adapter_new ();
+
+ dec->decoder = FLAC__stream_decoder_new ();
+
+ /* no point calculating since it's never checked here */
+ FLAC__stream_decoder_set_md5_checking (dec->decoder, false);
+ FLAC__stream_decoder_set_metadata_respond (dec->decoder,
+ FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ FLAC__stream_decoder_set_metadata_respond (dec->decoder,
+ FLAC__METADATA_TYPE_PICTURE);
+}
+
+static void
+gst_flac_dec_finalize (GObject * object)
+{
+ GstFlacDec *flacdec;
+
+ flacdec = GST_FLAC_DEC (object);
+
+ gst_flac_dec_reset_decoders (flacdec);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static gboolean
+gst_flac_dec_update_metadata (GstFlacDec * flacdec,
+ const FLAC__StreamMetadata * metadata)
+{
+ GstTagList *list;
+ guint num, i;
+
+ if (flacdec->tags)
+ list = flacdec->tags;
+ else
+ flacdec->tags = list = gst_tag_list_new ();
+
+ num = metadata->data.vorbis_comment.num_comments;
+ GST_DEBUG_OBJECT (flacdec, "%u tag(s) found", num);
+
+ for (i = 0; i < num; ++i) {
+ gchar *vc, *name, *value;
+
+ vc = g_strndup ((gchar *) metadata->data.vorbis_comment.comments[i].entry,
+ metadata->data.vorbis_comment.comments[i].length);
+
+ if (gst_tag_parse_extended_comment (vc, &name, NULL, &value, TRUE)) {
+ GST_DEBUG_OBJECT (flacdec, "%s : %s", name, value);
+ if (value && strlen (value))
+ gst_vorbis_tag_add (list, name, value);
+ g_free (name);
+ g_free (value);
+ }
+
+ g_free (vc);
+ }
+
+ return TRUE;
+}
+
+/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
+static const guint8 crc8_table[256] = {
+ 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
+ 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+ 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
+ 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+ 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
+ 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+ 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
+ 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+ 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
+ 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+ 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
+ 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+ 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
+ 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+ 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
+ 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+ 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
+ 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+ 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
+ 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+ 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
+ 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+ 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
+ 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+ 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
+ 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+ 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
+ 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+ 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
+ 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+ 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
+ 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+};
+
+static guint8
+gst_flac_calculate_crc8 (guint8 * data, guint length)
+{
+ guint8 crc = 0;
+
+ while (length--) {
+ crc = crc8_table[crc ^ *data];
+ ++data;
+ }
+
+ return crc;
+}
+
+static gboolean
+gst_flac_dec_scan_got_frame (GstFlacDec * flacdec, guint8 * data, guint size,
+ gint64 * last_sample_num)
+{
+ guint headerlen;
+ guint sr_from_end = 0; /* can be 0, 8 or 16 */
+ guint bs_from_end = 0; /* can be 0, 8 or 16 */
+ guint32 val = 0;
+ guint8 bs, sr, ca, ss, pb;
+
+ if (size < 10)
+ return FALSE;
+
+ /* sync */
+ if (data[0] != 0xFF || (data[1] & 0xFC) != 0xF8)
+ return FALSE;
+ if (data[1] & 1) {
+ GST_WARNING_OBJECT (flacdec, "Variable block size FLAC unsupported");
+ return FALSE;
+ }
+
+ bs = (data[2] & 0xF0) >> 4; /* blocksize marker */
+ sr = (data[2] & 0x0F); /* samplerate marker */
+ ca = (data[3] & 0xF0) >> 4; /* channel assignment */
+ ss = (data[3] & 0x0F) >> 1; /* sample size marker */
+ pb = (data[3] & 0x01); /* padding bit */
+
+ GST_LOG_OBJECT (flacdec,
+ "got sync, bs=%x,sr=%x,ca=%x,ss=%x,pb=%x", bs, sr, ca, ss, pb);
+
+ if (bs == 0 || sr == 0x0F || ca >= 0x0B || ss == 0x03 || ss == 0x07) {
+ return FALSE;
+ }
+
+ /* read block size from end of header? */
+ if (bs == 6)
+ bs_from_end = 8;
+ else if (bs == 7)
+ bs_from_end = 16;
+
+ /* read sample rate from end of header? */
+ if (sr == 0x0C)
+ sr_from_end = 8;
+ else if (sr == 0x0D || sr == 0x0E)
+ sr_from_end = 16;
+
+ /* FIXME: This is can be 36 bit if variable block size is used,
+ * fortunately not encoder supports this yet and we check for that
+ * above.
+ */
+ val = (guint32) g_utf8_get_char_validated ((gchar *) data + 4, -1);
+
+ if (val == (guint32) - 1 || val == (guint32) - 2) {
+ GST_LOG_OBJECT (flacdec, "failed to read sample/frame");
+ return FALSE;
+ }
+
+ headerlen = 4 + g_unichar_to_utf8 ((gunichar) val, NULL) +
+ (bs_from_end / 8) + (sr_from_end / 8);
+
+ if (gst_flac_calculate_crc8 (data, headerlen) != data[headerlen]) {
+ GST_LOG_OBJECT (flacdec, "invalid checksum");
+ return FALSE;
+ }
+
+ if (flacdec->min_blocksize == flacdec->max_blocksize) {
+ *last_sample_num = (val + 1) * flacdec->min_blocksize;
+ } else {
+ *last_sample_num = 0; /* FIXME: + length of last block in samples */
+ }
+
+ /* FIXME: only valid for fixed block size streams */
+ GST_DEBUG_OBJECT (flacdec, "frame number: %" G_GINT64_FORMAT,
+ *last_sample_num);
+
+ if (flacdec->sample_rate > 0 && *last_sample_num != 0) {
+ GST_DEBUG_OBJECT (flacdec, "last sample %" G_GINT64_FORMAT " = %"
+ GST_TIME_FORMAT, *last_sample_num,
+ GST_TIME_ARGS (*last_sample_num * GST_SECOND / flacdec->sample_rate));
+ }
+
+ return TRUE;
+}
+
+#define SCANBLOCK_SIZE (64*1024)
+
+static void
+gst_flac_dec_scan_for_last_block (GstFlacDec * flacdec, gint64 * samples)
+{
+ GstFormat format = GST_FORMAT_BYTES;
+ gint64 file_size, offset;
+
+ GST_INFO_OBJECT (flacdec, "total number of samples unknown, scanning file");
+
+ if (!gst_pad_query_peer_duration (flacdec->sinkpad, &format, &file_size)) {
+ GST_WARNING_OBJECT (flacdec, "failed to query upstream size!");
+ return;
+ }
+
+ if (flacdec->min_blocksize != flacdec->max_blocksize) {
+ GST_WARNING_OBJECT (flacdec, "scanning for last sample only works "
+ "for FLAC files with constant blocksize");
+ return;
+ }
+
+ GST_DEBUG_OBJECT (flacdec, "upstream size: %" G_GINT64_FORMAT, file_size);
+
+ offset = file_size - 1;
+ while (offset >= MAX (SCANBLOCK_SIZE / 2, file_size / 2)) {
+ GstFlowReturn flow;
+ GstBuffer *buf = NULL;
+ guint8 *data;
+ guint size;
+
+ /* divide by 2 = not very sophisticated way to deal with overlapping */
+ offset -= SCANBLOCK_SIZE / 2;
+ GST_LOG_OBJECT (flacdec, "looking for frame at %" G_GINT64_FORMAT
+ "-%" G_GINT64_FORMAT, offset, offset + SCANBLOCK_SIZE);
+
+ flow = gst_pad_pull_range (flacdec->sinkpad, offset, SCANBLOCK_SIZE, &buf);
+ if (flow != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (flacdec, "flow = %s", gst_flow_get_name (flow));
+ return;
+ }
+
+ size = GST_BUFFER_SIZE (buf);
+ data = GST_BUFFER_DATA (buf);
+
+ while (size > 16) {
+ if (gst_flac_dec_scan_got_frame (flacdec, data, size, samples)) {
+ GST_DEBUG_OBJECT (flacdec, "frame sync at offset %" G_GINT64_FORMAT,
+ offset + GST_BUFFER_SIZE (buf) - size);
+ gst_buffer_unref (buf);
+ return;
+ }
+ ++data;
+ --size;
+ }
+
+ gst_buffer_unref (buf);
+ }
+}
+
+static void
+gst_flac_extract_picture_buffer (GstFlacDec * dec,
+ const FLAC__StreamMetadata * metadata)
+{
+ FLAC__StreamMetadata_Picture picture;
+ GstTagList *tags;
+
+ g_return_if_fail (metadata->type == FLAC__METADATA_TYPE_PICTURE);
+
+ GST_LOG_OBJECT (dec, "Got PICTURE block");
+ picture = metadata->data.picture;
+
+ GST_DEBUG_OBJECT (dec, "declared MIME type is: '%s'",
+ GST_STR_NULL (picture.mime_type));
+ GST_DEBUG_OBJECT (dec, "image data is %u bytes", picture.data_length);
+
+ tags = gst_tag_list_new ();
+
+ gst_tag_list_add_id3_image (tags, (guint8 *) picture.data,
+ picture.data_length, picture.type);
+
+ if (!gst_tag_list_is_empty (tags)) {
+ gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, tags);
+ } else {
+ GST_DEBUG_OBJECT (dec, "problem parsing PICTURE block, skipping");
+ gst_tag_list_free (tags);
+ }
+}
+
+static void
+gst_flac_dec_metadata_cb (const FLAC__StreamDecoder * decoder,
+ const FLAC__StreamMetadata * metadata, void *client_data)
+{
+ GstFlacDec *flacdec = GST_FLAC_DEC (client_data);
+
+ GST_LOG_OBJECT (flacdec, "metadata type: %d", metadata->type);
+
+ switch (metadata->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:{
+ gint64 samples;
+ guint depth;
+
+ samples = metadata->data.stream_info.total_samples;
+
+ flacdec->min_blocksize = metadata->data.stream_info.min_blocksize;
+ flacdec->max_blocksize = metadata->data.stream_info.max_blocksize;
+ flacdec->sample_rate = metadata->data.stream_info.sample_rate;
+ flacdec->depth = depth = metadata->data.stream_info.bits_per_sample;
+ flacdec->channels = metadata->data.stream_info.channels;
+
+ if (depth < 9)
+ flacdec->width = 8;
+ else if (depth < 17)
+ flacdec->width = 16;
+ else
+ flacdec->width = 32;
+
+ GST_DEBUG_OBJECT (flacdec, "blocksize: min=%u, max=%u",
+ flacdec->min_blocksize, flacdec->max_blocksize);
+ GST_DEBUG_OBJECT (flacdec, "sample rate: %u, channels: %u",
+ flacdec->sample_rate, flacdec->channels);
+ GST_DEBUG_OBJECT (flacdec, "depth: %u, width: %u", flacdec->depth,
+ flacdec->width);
+
+ /* Only scan for last block in pull-mode, since it uses pull_range() */
+ if (samples == 0 && !flacdec->streaming) {
+ gst_flac_dec_scan_for_last_block (flacdec, &samples);
+ }
+
+ GST_DEBUG_OBJECT (flacdec, "total samples = %" G_GINT64_FORMAT, samples);
+
+ /* in framed mode the demuxer/parser upstream has already pushed a
+ * newsegment event in TIME format which we've passed on */
+ if (samples > 0 && !flacdec->framed) {
+ gint64 duration;
+
+ gst_segment_set_duration (&flacdec->segment, GST_FORMAT_DEFAULT,
+ samples);
+
+ /* convert duration to time */
+ duration = gst_util_uint64_scale_int (samples, GST_SECOND,
+ flacdec->sample_rate);
+
+ /* fixme, at this time we could seek to the queued seek event if we have
+ * any */
+ if (flacdec->start_segment)
+ gst_event_unref (flacdec->start_segment);
+ flacdec->start_segment =
+ gst_event_new_new_segment_full (FALSE,
+ flacdec->segment.rate, flacdec->segment.applied_rate,
+ GST_FORMAT_TIME, 0, duration, 0);
+ }
+ break;
+ }
+ case FLAC__METADATA_TYPE_PICTURE:{
+ gst_flac_extract_picture_buffer (flacdec, metadata);
+ break;
+ }
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ gst_flac_dec_update_metadata (flacdec, metadata);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_flac_dec_error_cb (const FLAC__StreamDecoder * d,
+ FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ const gchar *error;
+ GstFlacDec *dec;
+
+ dec = GST_FLAC_DEC (client_data);
+
+ switch (status) {
+ case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
+ /* Ignore this error and keep processing */
+ return;
+ case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
+ error = "bad header";
+ break;
+ case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
+ error = "CRC mismatch";
+ break;
+ default:
+ error = "unknown error";
+ break;
+ }
+
+ GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("%s (%d)", error, status));
+ dec->last_flow = GST_FLOW_ERROR;
+}
+
+static FLAC__StreamDecoderSeekStatus
+gst_flac_dec_seek (const FLAC__StreamDecoder * decoder,
+ FLAC__uint64 position, void *client_data)
+{
+ GstFlacDec *flacdec;
+
+ flacdec = GST_FLAC_DEC (client_data);
+
+ GST_DEBUG_OBJECT (flacdec, "seek %" G_GUINT64_FORMAT, (guint64) position);
+ flacdec->offset = position;
+
+ return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+static FLAC__StreamDecoderTellStatus
+gst_flac_dec_tell (const FLAC__StreamDecoder * decoder,
+ FLAC__uint64 * position, void *client_data)
+{
+ GstFlacDec *flacdec;
+
+ flacdec = GST_FLAC_DEC (client_data);
+
+ *position = flacdec->offset;
+
+ GST_DEBUG_OBJECT (flacdec, "tell %" G_GINT64_FORMAT, (gint64) * position);
+
+ return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+
+static FLAC__StreamDecoderLengthStatus
+gst_flac_dec_length (const FLAC__StreamDecoder * decoder,
+ FLAC__uint64 * length, void *client_data)
+{
+ GstFlacDec *flacdec;
+ GstFormat fmt = GST_FORMAT_BYTES;
+ gint64 len = -1;
+
+ flacdec = GST_FLAC_DEC (client_data);
+
+ if (!gst_pad_query_peer_duration (flacdec->sinkpad, &fmt, &len) ||
+ (fmt != GST_FORMAT_BYTES || len == -1))
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+
+ *length = len;
+
+ GST_DEBUG_OBJECT (flacdec, "encoded byte length %" G_GINT64_FORMAT,
+ (gint64) * length);
+
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+static FLAC__bool
+gst_flac_dec_eof (const FLAC__StreamDecoder * decoder, void *client_data)
+{
+ GstFlacDec *flacdec;
+ GstFormat fmt;
+ GstPad *peer;
+ gboolean ret = FALSE;
+ gint64 len;
+
+ flacdec = GST_FLAC_DEC (client_data);
+
+ if (!(peer = gst_pad_get_peer (flacdec->sinkpad))) {
+ GST_WARNING_OBJECT (flacdec, "no peer pad, returning EOF");
+ return TRUE;
+ }
+
+ fmt = GST_FORMAT_BYTES;
+ if (gst_pad_query_duration (peer, &fmt, &len) && fmt == GST_FORMAT_BYTES &&
+ len != -1 && flacdec->offset >= len) {
+ GST_DEBUG_OBJECT (flacdec,
+ "offset=%" G_GINT64_FORMAT ", len=%" G_GINT64_FORMAT
+ ", returning EOF", flacdec->offset, len);
+ ret = TRUE;
+ }
+
+ gst_object_unref (peer);
+
+ return ret;
+}
+
+static FLAC__StreamDecoderReadStatus
+gst_flac_dec_read_seekable (const FLAC__StreamDecoder * decoder,
+ FLAC__byte buffer[], size_t * bytes, void *client_data)
+{
+ GstFlowReturn flow;
+ GstFlacDec *flacdec;
+ GstBuffer *buf;
+
+ flacdec = GST_FLAC_DEC (client_data);
+
+ flow = gst_pad_pull_range (flacdec->sinkpad, flacdec->offset, *bytes, &buf);
+
+ GST_PAD_STREAM_LOCK (flacdec->sinkpad);
+ flacdec->pull_flow = flow;
+ GST_PAD_STREAM_UNLOCK (flacdec->sinkpad);
+
+ if (G_UNLIKELY (flow != GST_FLOW_OK)) {
+ GST_INFO_OBJECT (flacdec, "pull_range flow: %s", gst_flow_get_name (flow));
+ if (flow == GST_FLOW_UNEXPECTED)
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+
+ GST_DEBUG_OBJECT (flacdec, "Read %d bytes at %" G_GUINT64_FORMAT,
+ GST_BUFFER_SIZE (buf), flacdec->offset);
+ memcpy (buffer, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+ *bytes = GST_BUFFER_SIZE (buf);
+ gst_buffer_unref (buf);
+ flacdec->offset += *bytes;
+
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
+static FLAC__StreamDecoderReadStatus
+gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder,
+ FLAC__byte buffer[], size_t * bytes, void *client_data)
+{
+ GstFlacDec *dec = GST_FLAC_DEC (client_data);
+ guint len;
+
+ len = MIN (gst_adapter_available (dec->adapter), *bytes);
+
+ if (len == 0) {
+ GST_LOG_OBJECT (dec, "0 bytes available at the moment");
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+
+ GST_LOG_OBJECT (dec, "feeding %u bytes to decoder (available=%u, bytes=%u)",
+ len, gst_adapter_available (dec->adapter), (guint) * bytes);
+ gst_adapter_copy (dec->adapter, buffer, 0, len);
+ *bytes = len;
+
+ gst_adapter_flush (dec->adapter, len);
+
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
+static FLAC__StreamDecoderWriteStatus
+gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
+ const FLAC__int32 * const buffer[])
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstBuffer *outbuf;
+ guint depth = frame->header.bits_per_sample;
+ guint width;
+ guint sample_rate = frame->header.sample_rate;
+ guint channels = frame->header.channels;
+ guint samples = frame->header.blocksize;
+ guint j, i;
+ GstClockTime next;
+
+ GST_LOG_OBJECT (flacdec, "samples in frame header: %d", samples);
+
+ /* if a DEFAULT segment is configured, don't send samples past the end
+ * of the segment */
+ if (flacdec->segment.format == GST_FORMAT_DEFAULT &&
+ flacdec->segment.stop != -1 &&
+ flacdec->segment.last_stop >= 0 &&
+ flacdec->segment.last_stop + samples > flacdec->segment.stop) {
+ samples = flacdec->segment.stop - flacdec->segment.last_stop;
+ GST_DEBUG_OBJECT (flacdec,
+ "clipping last buffer to %d samples because of segment", samples);
+ }
+
+ switch (depth) {
+ case 8:
+ width = 8;
+ break;
+ case 12:
+ case 16:
+ width = 16;
+ break;
+ case 20:
+ case 24:
+ case 32:
+ width = 32;
+ break;
+ case 0:
+ if (flacdec->depth < 4 || flacdec->depth > 32) {
+ GST_ERROR_OBJECT (flacdec, "unsupported depth %d from STREAMINFO",
+ flacdec->depth);
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+
+ depth = flacdec->depth;
+ if (depth < 9)
+ width = 8;
+ else if (depth < 17)
+ width = 16;
+ else
+ width = 32;
+
+ break;
+ default:
+ GST_ERROR_OBJECT (flacdec, "unsupported depth %d", depth);
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+
+ if (sample_rate == 0) {
+ if (flacdec->sample_rate != 0) {
+ sample_rate = flacdec->sample_rate;
+ } else {
+ GST_ERROR_OBJECT (flacdec, "unknown sample rate");
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+ }
+
+ if (!GST_PAD_CAPS (flacdec->srcpad)) {
+ GstCaps *caps;
+
+ GST_DEBUG_OBJECT (flacdec, "Negotiating %d Hz @ %d channels",
+ frame->header.sample_rate, channels);
+
+ caps = gst_caps_new_simple ("audio/x-raw-int",
+ "endianness", G_TYPE_INT, G_BYTE_ORDER,
+ "signed", G_TYPE_BOOLEAN, TRUE,
+ "width", G_TYPE_INT, width,
+ "depth", G_TYPE_INT, depth,
+ "rate", G_TYPE_INT, frame->header.sample_rate,
+ "channels", G_TYPE_INT, channels, NULL);
+
+ if (channels > 2) {
+ GstStructure *s = gst_caps_get_structure (caps, 0);
+
+ gst_audio_set_channel_positions (s, channel_positions[channels - 1]);
+ }
+
+ flacdec->depth = depth;
+ flacdec->width = width;
+ flacdec->channels = channels;
+ flacdec->sample_rate = sample_rate;
+
+ gst_pad_set_caps (flacdec->srcpad, caps);
+ gst_caps_unref (caps);
+ }
+
+ if (flacdec->close_segment) {
+ GST_DEBUG_OBJECT (flacdec, "pushing close segment");
+ gst_pad_push_event (flacdec->srcpad, flacdec->close_segment);
+ flacdec->close_segment = NULL;
+ }
+ if (flacdec->start_segment) {
+ GST_DEBUG_OBJECT (flacdec, "pushing start segment");
+ gst_pad_push_event (flacdec->srcpad, flacdec->start_segment);
+ flacdec->start_segment = NULL;
+ }
+
+ if (flacdec->tags) {
+ gst_element_found_tags_for_pad (GST_ELEMENT (flacdec), flacdec->srcpad,
+ flacdec->tags);
+ flacdec->tags = NULL;
+ }
+
+ if (flacdec->pending) {
+ GST_DEBUG_OBJECT (flacdec,
+ "pushing pending samples at offset %" G_GINT64_FORMAT " (%"
+ GST_TIME_FORMAT " + %" GST_TIME_FORMAT ")",
+ GST_BUFFER_OFFSET (flacdec->pending),
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (flacdec->pending)),
+ GST_TIME_ARGS (GST_BUFFER_DURATION (flacdec->pending)));
+ /* Pending buffer was always allocated from the seeking thread,
+ * which means it wasn't gst_buffer_alloc'd. Do so now to let
+ * downstream negotiation work on older basetransform */
+ ret = gst_pad_alloc_buffer_and_set_caps (flacdec->srcpad,
+ GST_BUFFER_OFFSET (flacdec->pending),
+ GST_BUFFER_SIZE (flacdec->pending),
+ GST_BUFFER_CAPS (flacdec->pending), &outbuf);
+ if (ret == GST_FLOW_OK) {
+ gst_pad_push (flacdec->srcpad, flacdec->pending);
+ gst_buffer_unref (outbuf);
+ }
+
+ outbuf = flacdec->pending = NULL;
+ flacdec->segment.last_stop += flacdec->pending_samples;
+ flacdec->pending_samples = 0;
+ }
+
+ if (flacdec->seeking) {
+ GST_DEBUG_OBJECT (flacdec, "a pad_alloc would block here, do normal alloc");
+ outbuf = gst_buffer_new_and_alloc (samples * channels * (width / 8));
+ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (flacdec->srcpad));
+ GST_BUFFER_OFFSET (outbuf) = flacdec->segment.last_stop;
+ } else {
+ GST_LOG_OBJECT (flacdec, "alloc_buffer_and_set_caps");
+ ret = gst_pad_alloc_buffer_and_set_caps (flacdec->srcpad,
+ flacdec->segment.last_stop, samples * channels * (width / 8),
+ GST_PAD_CAPS (flacdec->srcpad), &outbuf);
+
+ if (ret != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (flacdec, "gst_pad_alloc_buffer() returned %s",
+ gst_flow_get_name (ret));
+ goto done;
+ }
+ }
+
+ if (flacdec->cur_granulepos != GST_BUFFER_OFFSET_NONE) {
+ /* this should be fine since it should be one flac frame per ogg packet */
+ /* note the + 1, as the granpos is the presentation time of the last sample,
+ whereas the last stop represents the end time of that sample */
+ flacdec->segment.last_stop = flacdec->cur_granulepos - samples + 1;
+ GST_LOG_OBJECT (flacdec, "granulepos = %" G_GINT64_FORMAT ", samples = %u",
+ flacdec->cur_granulepos, samples);
+ }
+
+ GST_BUFFER_TIMESTAMP (outbuf) =
+ gst_util_uint64_scale_int (flacdec->segment.last_stop, GST_SECOND,
+ frame->header.sample_rate);
+
+ /* get next timestamp to calculate the duration */
+ next = gst_util_uint64_scale_int (flacdec->segment.last_stop + samples,
+ GST_SECOND, frame->header.sample_rate);
+
+ GST_BUFFER_DURATION (outbuf) = next - GST_BUFFER_TIMESTAMP (outbuf);
+
+ if (width == 8) {
+ gint8 *outbuffer = (gint8 *) GST_BUFFER_DATA (outbuf);
+
+ for (i = 0; i < samples; i++) {
+ for (j = 0; j < channels; j++) {
+ *outbuffer++ = (gint8) buffer[j][i];
+ }
+ }
+ } else if (width == 16) {
+ gint16 *outbuffer = (gint16 *) GST_BUFFER_DATA (outbuf);
+
+ for (i = 0; i < samples; i++) {
+ for (j = 0; j < channels; j++) {
+ *outbuffer++ = (gint16) buffer[j][i];
+ }
+ }
+ } else if (width == 32) {
+ gint32 *outbuffer = (gint32 *) GST_BUFFER_DATA (outbuf);
+
+ for (i = 0; i < samples; i++) {
+ for (j = 0; j < channels; j++) {
+ *outbuffer++ = (gint32) buffer[j][i];
+ }
+ }
+ } else {
+ g_assert_not_reached ();
+ }
+
+ if (!flacdec->seeking) {
+ GST_DEBUG_OBJECT (flacdec, "pushing %d samples at offset %" G_GINT64_FORMAT
+ " (%" GST_TIME_FORMAT " + %" GST_TIME_FORMAT ")",
+ samples, GST_BUFFER_OFFSET (outbuf),
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+ GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
+
+ if (flacdec->discont) {
+ GST_DEBUG_OBJECT (flacdec, "marking discont");
+ outbuf = gst_buffer_make_metadata_writable (outbuf);
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ flacdec->discont = FALSE;
+ }
+ ret = gst_pad_push (flacdec->srcpad, outbuf);
+ GST_DEBUG_OBJECT (flacdec, "returned %s", gst_flow_get_name (ret));
+ flacdec->segment.last_stop += samples;
+ } else {
+ GST_DEBUG_OBJECT (flacdec,
+ "not pushing %d samples at offset %" G_GINT64_FORMAT
+ " (in seek)", samples, GST_BUFFER_OFFSET (outbuf));
+ gst_buffer_replace (&flacdec->pending, outbuf);
+ gst_buffer_unref (outbuf);
+ flacdec->pending_samples = samples;
+ ret = GST_FLOW_OK;
+ }
+
+ if (ret != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (flacdec, "gst_pad_push() returned %s",
+ gst_flow_get_name (ret));
+ }
+
+done:
+
+
+ /* we act on the flow return value later in the loop function, as we don't
+ * want to mess up the internal decoder state by returning ABORT when the
+ * error is in fact non-fatal (like a pad in flushing mode) and we want
+ * to continue later. So just pretend everything's dandy and act later. */
+ flacdec->last_flow = ret;
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static FLAC__StreamDecoderWriteStatus
+gst_flac_dec_write_stream (const FLAC__StreamDecoder * decoder,
+ const FLAC__Frame * frame,
+ const FLAC__int32 * const buffer[], void *client_data)
+{
+ return gst_flac_dec_write (GST_FLAC_DEC (client_data), frame, buffer);
+}
+
+static void
+gst_flac_dec_loop (GstPad * sinkpad)
+{
+ GstFlacDec *flacdec;
+ FLAC__StreamDecoderState s;
+ FLAC__StreamDecoderInitStatus is;
+
+ flacdec = GST_FLAC_DEC (GST_OBJECT_PARENT (sinkpad));
+
+ GST_LOG_OBJECT (flacdec, "entering loop");
+
+ if (flacdec->eos) {
+ GST_DEBUG_OBJECT (flacdec, "Seeked after end of file");
+
+ if (flacdec->close_segment) {
+ GST_DEBUG_OBJECT (flacdec, "pushing close segment");
+ gst_pad_push_event (flacdec->srcpad, flacdec->close_segment);
+ flacdec->close_segment = NULL;
+ }
+ if (flacdec->start_segment) {
+ GST_DEBUG_OBJECT (flacdec, "pushing start segment");
+ gst_pad_push_event (flacdec->srcpad, flacdec->start_segment);
+ flacdec->start_segment = NULL;
+ }
+
+ if (flacdec->tags) {
+ gst_element_found_tags_for_pad (GST_ELEMENT (flacdec), flacdec->srcpad,
+ flacdec->tags);
+ flacdec->tags = NULL;
+ }
+
+ if ((flacdec->segment.flags & GST_SEEK_FLAG_SEGMENT) == 0) {
+ goto eos_and_pause;
+ } else {
+ goto segment_done_and_pause;
+ }
+ }
+
+ if (flacdec->init) {
+ GST_DEBUG_OBJECT (flacdec, "initializing new decoder");
+ is = FLAC__stream_decoder_init_stream (flacdec->decoder,
+ gst_flac_dec_read_seekable, gst_flac_dec_seek, gst_flac_dec_tell,
+ gst_flac_dec_length, gst_flac_dec_eof, gst_flac_dec_write_stream,
+ gst_flac_dec_metadata_cb, gst_flac_dec_error_cb, flacdec);
+ if (is != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+ goto analyze_state;
+
+ /* FLAC__seekable_decoder_process_metadata (flacdec->decoder); */
+ flacdec->init = FALSE;
+ }
+
+ flacdec->cur_granulepos = GST_BUFFER_OFFSET_NONE;
+
+ flacdec->last_flow = GST_FLOW_OK;
+
+ GST_LOG_OBJECT (flacdec, "processing single");
+ FLAC__stream_decoder_process_single (flacdec->decoder);
+
+analyze_state:
+
+ GST_LOG_OBJECT (flacdec, "done processing, checking encoder state");
+ s = FLAC__stream_decoder_get_state (flacdec->decoder);
+ switch (s) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+ case FLAC__STREAM_DECODER_READ_METADATA:
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ case FLAC__STREAM_DECODER_READ_FRAME:
+ {
+ GST_DEBUG_OBJECT (flacdec, "everything ok");
+
+ if (flacdec->last_flow < GST_FLOW_UNEXPECTED ||
+ flacdec->last_flow == GST_FLOW_NOT_LINKED) {
+ GST_ELEMENT_ERROR (flacdec, STREAM, FAILED,
+ (_("Internal data stream error.")),
+ ("stream stopped, reason %s",
+ gst_flow_get_name (flacdec->last_flow)));
+ goto eos_and_pause;
+ } else if (flacdec->last_flow == GST_FLOW_UNEXPECTED) {
+ goto eos_and_pause;
+ } else if (flacdec->last_flow != GST_FLOW_OK) {
+ goto pause;
+ }
+
+ /* check if we're at the end of a configured segment */
+ if (flacdec->segment.stop != -1 &&
+ flacdec->segment.last_stop > 0 &&
+ flacdec->segment.last_stop >= flacdec->segment.stop) {
+ GST_DEBUG_OBJECT (flacdec, "reached end of the configured segment");
+
+ if ((flacdec->segment.flags & GST_SEEK_FLAG_SEGMENT) == 0) {
+ goto eos_and_pause;
+ } else {
+ goto segment_done_and_pause;
+ }
+
+ g_assert_not_reached ();
+ }
+
+ return;
+ }
+
+ case FLAC__STREAM_DECODER_END_OF_STREAM:{
+ GST_DEBUG_OBJECT (flacdec, "EOS");
+ FLAC__stream_decoder_reset (flacdec->decoder);
+
+ if ((flacdec->segment.flags & GST_SEEK_FLAG_SEGMENT) != 0) {
+ if (flacdec->segment.duration > 0) {
+ flacdec->segment.stop = flacdec->segment.duration;
+ } else {
+ flacdec->segment.stop = flacdec->segment.last_stop;
+ }
+ goto segment_done_and_pause;
+ }
+
+ goto eos_and_pause;
+ }
+
+ /* gst_flac_dec_read_seekable() returned ABORTED */
+ case FLAC__STREAM_DECODER_ABORTED:
+ {
+ GST_INFO_OBJECT (flacdec, "read aborted: last pull_range flow = %s",
+ gst_flow_get_name (flacdec->pull_flow));
+ if (flacdec->pull_flow == GST_FLOW_WRONG_STATE) {
+ /* it seems we need to flush the decoder here to reset the decoder
+ * state after the abort for FLAC__stream_decoder_seek_absolute()
+ * to work properly */
+ GST_DEBUG_OBJECT (flacdec, "flushing decoder to reset decoder state");
+ FLAC__stream_decoder_flush (flacdec->decoder);
+ goto pause;
+ }
+ /* fall through */
+ }
+ case FLAC__STREAM_DECODER_OGG_ERROR:
+ case FLAC__STREAM_DECODER_SEEK_ERROR:
+ case FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
+ case FLAC__STREAM_DECODER_UNINITIALIZED:
+ default:{
+ /* fixme: this error sucks -- should try to figure out when/if an more
+ specific error was already sent via the callback */
+ GST_ELEMENT_ERROR (flacdec, STREAM, DECODE, (NULL),
+ ("%s", FLAC__StreamDecoderStateString[s]));
+ goto eos_and_pause;
+ }
+ }
+
+ return;
+
+segment_done_and_pause:
+ {
+ gint64 stop_time;
+
+ stop_time = gst_util_uint64_scale_int (flacdec->segment.stop,
+ GST_SECOND, flacdec->sample_rate);
+
+ GST_DEBUG_OBJECT (flacdec, "posting SEGMENT_DONE message, stop time %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (stop_time));
+
+ gst_element_post_message (GST_ELEMENT (flacdec),
+ gst_message_new_segment_done (GST_OBJECT (flacdec),
+ GST_FORMAT_TIME, stop_time));
+
+ goto pause;
+ }
+eos_and_pause:
+ {
+ GST_DEBUG_OBJECT (flacdec, "sending EOS event");
+ flacdec->running = FALSE;
+ gst_pad_push_event (flacdec->srcpad, gst_event_new_eos ());
+ /* fall through to pause */
+ }
+pause:
+ {
+ GST_DEBUG_OBJECT (flacdec, "pausing");
+ gst_pad_pause_task (sinkpad);
+ return;
+ }
+}
+
+static gboolean
+gst_flac_dec_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstFlacDec *dec;
+ gboolean res;
+
+ dec = GST_FLAC_DEC (gst_pad_get_parent (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:{
+ if (dec->init == FALSE) {
+ FLAC__stream_decoder_flush (dec->decoder);
+ gst_adapter_clear (dec->adapter);
+ }
+ res = gst_pad_push_event (dec->srcpad, event);
+ break;
+ }
+ case GST_EVENT_NEWSEGMENT:{
+ GstFormat fmt;
+ gboolean update;
+ gdouble rate, applied_rate;
+ gint64 cur, stop, time;
+
+ gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
+ &fmt, &cur, &stop, &time);
+
+ if (fmt == GST_FORMAT_TIME) {
+ GstFormat dformat = GST_FORMAT_DEFAULT;
+
+ GST_DEBUG_OBJECT (dec, "newsegment event in TIME format => framed");
+ dec->framed = TRUE;
+ res = gst_pad_push_event (dec->srcpad, event);
+
+ /* this won't work for the first newsegment event though ... */
+ if (gst_flac_dec_convert_src (dec->srcpad, GST_FORMAT_TIME, cur,
+ &dformat, &cur) && cur != -1 &&
+ gst_flac_dec_convert_src (dec->srcpad, GST_FORMAT_TIME, stop,
+ &dformat, &stop) && stop != -1) {
+ gst_segment_set_newsegment_full (&dec->segment, update, rate,
+ applied_rate, dformat, cur, stop, time);
+ GST_DEBUG_OBJECT (dec, "segment %" GST_SEGMENT_FORMAT, &dec->segment);
+ } else {
+ GST_WARNING_OBJECT (dec, "couldn't convert time => samples");
+ }
+ } else if (fmt == GST_FORMAT_BYTES || TRUE) {
+ GST_DEBUG_OBJECT (dec, "newsegment event in %s format => not framed",
+ gst_format_get_name (fmt));
+ dec->framed = FALSE;
+
+ /* prepare generic newsegment event, for some reason our metadata
+ * callback where we usually set this up is not being called in
+ * push mode */
+ if (dec->start_segment)
+ gst_event_unref (dec->start_segment);
+ dec->start_segment = gst_event_new_new_segment (FALSE, 1.0,
+ GST_FORMAT_TIME, 0, -1, 0);
+
+ gst_event_unref (event);
+ res = TRUE;
+ }
+ break;
+ }
+ case GST_EVENT_EOS:{
+ GST_LOG_OBJECT (dec, "EOS, with %u bytes available in adapter",
+ gst_adapter_available (dec->adapter));
+ if (dec->init == FALSE) {
+ if (gst_adapter_available (dec->adapter) > 0) {
+ FLAC__stream_decoder_process_until_end_of_stream (dec->decoder);
+ }
+ FLAC__stream_decoder_flush (dec->decoder);
+ }
+ gst_adapter_clear (dec->adapter);
+ res = gst_pad_push_event (dec->srcpad, event);
+ break;
+ }
+ default:
+ res = gst_pad_event_default (pad, event);
+ break;
+ }
+
+ gst_object_unref (dec);
+
+ return res;
+}
+
+static gboolean
+gst_flac_dec_chain_parse_headers (GstFlacDec * dec)
+{
+ guint8 marker[4];
+ guint avail, off;
+
+ avail = gst_adapter_available (dec->adapter);
+ if (avail < 4)
+ return FALSE;
+
+ gst_adapter_copy (dec->adapter, marker, 0, 4);
+ if (strncmp ((const gchar *) marker, "fLaC", 4) != 0) {
+ GST_ERROR_OBJECT (dec, "Unexpected header, expected fLaC header");
+ return TRUE; /* abort header parsing */
+ }
+
+ GST_DEBUG_OBJECT (dec, "fLaC header : len 4 @ %7u", 0);
+
+ off = 4;
+ while (avail > (off + 1 + 3)) {
+ gboolean is_last;
+ guint8 mb_hdr[4];
+ guint len, block_type;
+
+ gst_adapter_copy (dec->adapter, mb_hdr, off, 4);
+
+ is_last = ((mb_hdr[0] & 0x80) == 0x80);
+ block_type = mb_hdr[0] & 0x7f;
+ len = GST_READ_UINT24_BE (mb_hdr + 1);
+ GST_DEBUG_OBJECT (dec, "Metadata block type %u: len %7u + 4 @ %7u%s",
+ block_type, len, off, (is_last) ? " (last)" : "");
+ off += 4 + len;
+
+ if (is_last)
+ break;
+
+ if (off >= avail) {
+ GST_LOG_OBJECT (dec, "Need more data: next offset %u > avail %u", off,
+ avail);
+ return FALSE;
+ }
+ }
+
+ /* want metadata blocks plus at least one frame */
+ return (off + FLAC__MAX_BLOCK_SIZE >= avail);
+}
+
+static GstFlowReturn
+gst_flac_dec_chain (GstPad * pad, GstBuffer * buf)
+{
+ FLAC__StreamDecoderInitStatus s;
+ GstFlacDec *dec;
+ gboolean got_audio_frame;
+
+ dec = GST_FLAC_DEC (GST_PAD_PARENT (pad));
+
+ GST_LOG_OBJECT (dec,
+ "buffer with ts=%" GST_TIME_FORMAT ", offset=%" G_GINT64_FORMAT
+ ", end_offset=%" G_GINT64_FORMAT ", size=%u",
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_OFFSET (buf),
+ GST_BUFFER_OFFSET_END (buf), GST_BUFFER_SIZE (buf));
+
+ if (dec->init) {
+ GST_DEBUG_OBJECT (dec, "initializing decoder");
+ s = FLAC__stream_decoder_init_stream (dec->decoder,
+ gst_flac_dec_read_stream, NULL, NULL, NULL, NULL,
+ gst_flac_dec_write_stream, gst_flac_dec_metadata_cb,
+ gst_flac_dec_error_cb, dec);
+ if (s != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ GST_ELEMENT_ERROR (GST_ELEMENT (dec), LIBRARY, INIT, (NULL), (NULL));
+ return GST_FLOW_ERROR;
+ }
+ GST_DEBUG_OBJECT (dec, "initialized (framed=%d)", dec->framed);
+ dec->init = FALSE;
+ } else if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
+ /* Clear the adapter and the decoder */
+ gst_adapter_clear (dec->adapter);
+ FLAC__stream_decoder_flush (dec->decoder);
+ }
+
+ if (dec->framed) {
+ gint64 unused;
+
+ /* check if this is a flac audio frame (rather than a header or junk) */
+ got_audio_frame = gst_flac_dec_scan_got_frame (dec, GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf), &unused);
+
+ /* oggdemux will set granulepos in OFFSET_END instead of timestamp */
+ if (G_LIKELY (got_audio_frame)) {
+ /* old oggdemux for now */
+ if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+ dec->cur_granulepos = GST_BUFFER_OFFSET_END (buf);
+ } else {
+ GstFormat dformat = GST_FORMAT_DEFAULT;
+
+ /* upstream (e.g. demuxer) presents us time,
+ * convert to default samples */
+ gst_flac_dec_convert_src (dec->srcpad, GST_FORMAT_TIME,
+ GST_BUFFER_TIMESTAMP (buf), &dformat, &dec->segment.last_stop);
+ dec->cur_granulepos = GST_BUFFER_OFFSET_NONE;
+ }
+ }
+ } else {
+ dec->cur_granulepos = GST_BUFFER_OFFSET_NONE;
+ got_audio_frame = TRUE;
+ }
+
+ gst_adapter_push (dec->adapter, buf);
+ buf = NULL;
+
+ dec->last_flow = GST_FLOW_OK;
+
+ if (!dec->framed) {
+ if (G_UNLIKELY (!dec->got_headers)) {
+ if (!gst_flac_dec_chain_parse_headers (dec)) {
+ GST_LOG_OBJECT (dec, "don't have metadata blocks yet, need more data");
+ goto out;
+ }
+ GST_INFO_OBJECT (dec, "have all metadata blocks now");
+ dec->got_headers = TRUE;
+ }
+
+ /* wait until we have at least 64kB because libflac's StreamDecoder
+ * interface is a bit dumb it seems (if we don't have as much data as
+ * it wants it will call our read callback repeatedly and the only
+ * way to stop that is to error out or EOS, which will affect the
+ * decoder state). And the decoder seems to always ask for MAX_BLOCK_SIZE
+ * bytes rather than the max. block size from the header). Requiring
+ * MAX_BLOCK_SIZE bytes here should make sure it always gets enough data
+ * to decode at least one block */
+ while (gst_adapter_available (dec->adapter) >= FLAC__MAX_BLOCK_SIZE &&
+ dec->last_flow == GST_FLOW_OK) {
+ GST_LOG_OBJECT (dec, "%u bytes available",
+ gst_adapter_available (dec->adapter));
+ if (!FLAC__stream_decoder_process_single (dec->decoder)) {
+ GST_DEBUG_OBJECT (dec, "process_single failed");
+ break;
+ }
+
+ if (FLAC__stream_decoder_get_state (dec->decoder) ==
+ FLAC__STREAM_DECODER_ABORTED) {
+ GST_WARNING_OBJECT (dec, "Read callback caused internal abort");
+ dec->last_flow = GST_FLOW_ERROR;
+ break;
+ }
+ }
+ } else if (dec->framed && got_audio_frame) {
+ /* framed - there should always be enough data to decode something */
+ GST_LOG_OBJECT (dec, "%u bytes available",
+ gst_adapter_available (dec->adapter));
+ if (G_UNLIKELY (!dec->got_headers)) {
+ /* The first time we get audio data, we know we got all the headers.
+ * We then loop until all the metadata is processed, then do an extra
+ * "process_single" step for the audio frame. */
+ GST_DEBUG_OBJECT (dec,
+ "First audio frame, ensuring all metadata is processed");
+ if (!FLAC__stream_decoder_process_until_end_of_metadata (dec->decoder)) {
+ GST_DEBUG_OBJECT (dec, "process_until_end_of_metadata failed");
+ }
+ GST_DEBUG_OBJECT (dec,
+ "All metadata is now processed, reading to process audio data");
+ dec->got_headers = TRUE;
+ }
+ if (!FLAC__stream_decoder_process_single (dec->decoder)) {
+ GST_DEBUG_OBJECT (dec, "process_single failed");
+ }
+ } else {
+ GST_DEBUG_OBJECT (dec, "don't have all headers yet");
+ }
+
+out:
+
+ return dec->last_flow;
+}
+
+static gboolean
+gst_flac_dec_convert_sink (GstFlacDec * dec, GstFormat src_format,
+ gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
+{
+ gboolean res = TRUE;
+
+ if (dec->width == 0 || dec->channels == 0 || dec->sample_rate == 0) {
+ /* no frame decoded yet */
+ GST_DEBUG_OBJECT (dec, "cannot convert: not set up yet");
+ return FALSE;
+ }
+
+ switch (src_format) {
+ case GST_FORMAT_BYTES:{
+ res = FALSE;
+ break;
+ }
+ case GST_FORMAT_DEFAULT:
+ switch (*dest_format) {
+ case GST_FORMAT_BYTES:
+ res = FALSE;
+ break;
+ case GST_FORMAT_TIME:
+ /* granulepos = sample */
+ *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
+ dec->sample_rate);
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ break;
+ case GST_FORMAT_TIME:
+ switch (*dest_format) {
+ case GST_FORMAT_BYTES:
+ res = FALSE;
+ break;
+ case GST_FORMAT_DEFAULT:
+ *dest_value = gst_util_uint64_scale_int (src_value,
+ dec->sample_rate, GST_SECOND);
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ return res;
+}
+
+static const GstQueryType *
+gst_flac_dec_get_sink_query_types (GstPad * pad)
+{
+ static const GstQueryType types[] = {
+ GST_QUERY_CONVERT,
+ 0,
+ };
+
+ return types;
+}
+
+static gboolean
+gst_flac_dec_sink_query (GstPad * pad, GstQuery * query)
+{
+ GstFlacDec *dec;
+ gboolean res = FALSE;
+
+ dec = GST_FLAC_DEC (gst_pad_get_parent (pad));
+
+ GST_LOG_OBJECT (dec, "%s query", GST_QUERY_TYPE_NAME (query));
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_CONVERT:{
+ GstFormat src_fmt, dest_fmt;
+
+ gint64 src_val, dest_val;
+
+ gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, NULL);
+
+ res = gst_flac_dec_convert_sink (dec, src_fmt, src_val, &dest_fmt,
+ &dest_val);
+
+ if (res) {
+ gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+ }
+ GST_LOG_OBJECT (dec, "conversion %s", (res) ? "ok" : "FAILED");
+ break;
+ }
+
+ default:{
+ res = gst_pad_query_default (pad, query);
+ break;
+ }
+ }
+
+ gst_object_unref (dec);
+ return res;
+}
+
+static gboolean
+gst_flac_dec_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
+ GstFormat * dest_format, gint64 * dest_value)
+{
+ GstFlacDec *flacdec = GST_FLAC_DEC (GST_PAD_PARENT (pad));
+ gboolean res = TRUE;
+ guint bytes_per_sample;
+ guint scale = 1;
+
+ if (flacdec->width == 0 || flacdec->channels == 0 ||
+ flacdec->sample_rate == 0) {
+ /* no frame decoded yet */
+ GST_DEBUG_OBJECT (flacdec, "cannot convert: not set up yet");
+ return FALSE;
+ }
+
+ bytes_per_sample = flacdec->channels * (flacdec->width / 8);
+
+ switch (src_format) {
+ case GST_FORMAT_BYTES:{
+ switch (*dest_format) {
+ case GST_FORMAT_DEFAULT:
+ *dest_value =
+ gst_util_uint64_scale_int (src_value, 1, bytes_per_sample);
+ break;
+ case GST_FORMAT_TIME:
+ {
+ gint byterate = bytes_per_sample * flacdec->sample_rate;
+
+ *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
+ byterate);
+ break;
+ }
+ default:
+ res = FALSE;
+ }
+ break;
+ }
+ case GST_FORMAT_DEFAULT:
+ switch (*dest_format) {
+ case GST_FORMAT_BYTES:
+ *dest_value = src_value * bytes_per_sample;
+ break;
+ case GST_FORMAT_TIME:
+ *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
+ flacdec->sample_rate);
+ break;
+ default:
+ res = FALSE;
+ }
+ break;
+ case GST_FORMAT_TIME:
+ switch (*dest_format) {
+ case GST_FORMAT_BYTES:
+ scale = bytes_per_sample;
+ case GST_FORMAT_DEFAULT:
+ *dest_value = gst_util_uint64_scale_int_round (src_value,
+ scale * flacdec->sample_rate, GST_SECOND);
+ break;
+ default:
+ res = FALSE;
+ }
+ break;
+ default:
+ res = FALSE;
+ }
+ return res;
+}
+
+static const GstQueryType *
+gst_flac_dec_get_src_query_types (GstPad * pad)
+{
+ static const GstQueryType types[] = {
+ GST_QUERY_POSITION,
+ GST_QUERY_DURATION,
+ GST_QUERY_CONVERT,
+ GST_QUERY_SEEKING,
+ 0,
+ };
+
+ return types;
+}
+
+static gboolean
+gst_flac_dec_src_query (GstPad * pad, GstQuery * query)
+{
+ GstFlacDec *flacdec;
+ gboolean res = TRUE;
+ GstPad *peer;
+
+ flacdec = GST_FLAC_DEC (gst_pad_get_parent (pad));
+ peer = gst_pad_get_peer (flacdec->sinkpad);
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_POSITION:{
+ GstFormat fmt;
+ gint64 pos;
+
+ gst_query_parse_position (query, &fmt, NULL);
+
+ /* there might be a demuxer in front of us who can handle this */
+ if (fmt == GST_FORMAT_TIME && (res = gst_pad_query (peer, query)))
+ break;
+
+ if (fmt != GST_FORMAT_DEFAULT) {
+ if (!gst_flac_dec_convert_src (flacdec->srcpad, GST_FORMAT_DEFAULT,
+ flacdec->segment.last_stop, &fmt, &pos)) {
+ GST_DEBUG_OBJECT (flacdec, "failed to convert position into %s "
+ "format", gst_format_get_name (fmt));
+ res = FALSE;
+ goto done;
+ }
+ } else {
+ pos = flacdec->segment.last_stop;
+ }
+
+ gst_query_set_position (query, fmt, pos);
+
+ GST_DEBUG_OBJECT (flacdec, "returning position %" G_GUINT64_FORMAT
+ " (format: %s)", pos, gst_format_get_name (fmt));
+
+ res = TRUE;
+ break;
+ }
+
+ case GST_QUERY_DURATION:{
+ GstFormat fmt;
+ gint64 len;
+
+ gst_query_parse_duration (query, &fmt, NULL);
+
+ /* try any demuxers or parsers before us first */
+ if ((fmt == GST_FORMAT_TIME || fmt == GST_FORMAT_DEFAULT) &&
+ peer != NULL && gst_pad_query (peer, query)) {
+ gst_query_parse_duration (query, NULL, &len);
+ GST_DEBUG_OBJECT (flacdec, "peer returned duration %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (len));
+ res = TRUE;
+ goto done;
+ }
+
+ if (flacdec->segment.duration == 0 || flacdec->segment.duration == -1) {
+ GST_DEBUG_OBJECT (flacdec, "duration not known yet");
+ res = FALSE;
+ goto done;
+ }
+
+ /* convert total number of samples to request format */
+ if (fmt != GST_FORMAT_DEFAULT) {
+ if (!gst_flac_dec_convert_src (flacdec->srcpad, GST_FORMAT_DEFAULT,
+ flacdec->segment.duration, &fmt, &len)) {
+ GST_DEBUG_OBJECT (flacdec, "failed to convert duration into %s "
+ "format", gst_format_get_name (fmt));
+ res = FALSE;
+ goto done;
+ }
+ } else {
+ len = flacdec->segment.duration;
+ }
+
+ gst_query_set_duration (query, fmt, len);
+
+ GST_DEBUG_OBJECT (flacdec, "returning duration %" G_GUINT64_FORMAT
+ " (format: %s)", len, gst_format_get_name (fmt));
+
+ res = TRUE;
+ break;
+ }
+
+ case GST_QUERY_CONVERT:{
+ GstFormat src_fmt, dest_fmt;
+ gint64 src_val, dest_val;
+
+ gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, NULL);
+
+ res = gst_flac_dec_convert_src (pad, src_fmt, src_val, &dest_fmt,
+ &dest_val);
+
+ if (res) {
+ gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+ }
+
+ break;
+ }
+ case GST_QUERY_SEEKING:{
+ GstFormat fmt;
+ gboolean seekable = FALSE;
+
+ res = TRUE;
+ /* If upstream can handle the query we're done */
+ seekable = gst_pad_peer_query (flacdec->sinkpad, query);
+ if (seekable)
+ gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
+ if (seekable)
+ goto done;
+
+ gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
+ if ((fmt != GST_FORMAT_TIME && fmt != GST_FORMAT_DEFAULT) ||
+ flacdec->streaming) {
+ gst_query_set_seeking (query, fmt, FALSE, -1, -1);
+ } else {
+ gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0, -1);
+ }
+ break;
+ }
+
+ default:{
+ res = gst_pad_query_default (pad, query);
+ break;
+ }
+ }
+
+done:
+
+ if (peer)
+ gst_object_unref (peer);
+
+ gst_object_unref (flacdec);
+
+ return res;
+}
+
+static gboolean
+gst_flac_dec_handle_seek_event (GstFlacDec * flacdec, GstEvent * event)
+{
+ FLAC__bool seek_ok;
+ GstSeekFlags seek_flags;
+ GstSeekType start_type;
+ GstSeekType stop_type;
+ GstSegment segment;
+ GstFormat seek_format;
+ gboolean only_update = FALSE;
+ gboolean flush;
+ gdouble rate;
+ gint64 start, last_stop;
+ gint64 stop;
+
+ if (flacdec->streaming) {
+ GST_DEBUG_OBJECT (flacdec, "seeking in streaming mode not implemented yet");
+ return FALSE;
+ }
+
+ gst_event_parse_seek (event, &rate, &seek_format, &seek_flags, &start_type,
+ &start, &stop_type, &stop);
+
+ if (seek_format != GST_FORMAT_DEFAULT && seek_format != GST_FORMAT_TIME) {
+ GST_DEBUG_OBJECT (flacdec,
+ "seeking is only supported in TIME or DEFAULT format");
+ return FALSE;
+ }
+
+ if (rate < 0.0) {
+ GST_DEBUG_OBJECT (flacdec,
+ "only forward playback supported, rate %f not allowed", rate);
+ return FALSE;
+ }
+
+ if (seek_format != GST_FORMAT_DEFAULT) {
+ GstFormat target_format = GST_FORMAT_DEFAULT;
+
+ if (start_type != GST_SEEK_TYPE_NONE &&
+ !gst_flac_dec_convert_src (flacdec->srcpad, seek_format, start,
+ &target_format, &start)) {
+ GST_DEBUG_OBJECT (flacdec, "failed to convert start to DEFAULT format");
+ return FALSE;
+ }
+
+ if (stop_type != GST_SEEK_TYPE_NONE &&
+ !gst_flac_dec_convert_src (flacdec->srcpad, seek_format, stop,
+ &target_format, &stop)) {
+ GST_DEBUG_OBJECT (flacdec, "failed to convert stop to DEFAULT format");
+ return FALSE;
+ }
+ }
+
+ /* Check if we seeked after the end of file */
+ if (start_type != GST_SEEK_TYPE_NONE && flacdec->segment.duration > 0 &&
+ start >= flacdec->segment.duration) {
+ flacdec->eos = TRUE;
+ } else {
+ flacdec->eos = FALSE;
+ }
+
+ flush = ((seek_flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
+
+ if (flush) {
+ /* flushing seek, clear the pipeline of stuff, we need a newsegment after
+ * this. */
+ GST_DEBUG_OBJECT (flacdec, "flushing");
+ gst_pad_push_event (flacdec->sinkpad, gst_event_new_flush_start ());
+ gst_pad_push_event (flacdec->srcpad, gst_event_new_flush_start ());
+ } else {
+ /* non flushing seek, pause the task */
+ GST_DEBUG_OBJECT (flacdec, "stopping task");
+ gst_pad_stop_task (flacdec->sinkpad);
+ }
+
+ /* acquire the stream lock, this either happens when the streaming thread
+ * stopped because of the flush or when the task is paused after the loop
+ * function finished an iteration, which can never happen when it's blocked
+ * downstream in PAUSED, for example */
+ GST_PAD_STREAM_LOCK (flacdec->sinkpad);
+
+ /* start seek with clear state to avoid seeking thread pushing segments/data.
+ * Note current state may have some pending,
+ * e.g. multi-sink seek leads to immediate subsequent seek events */
+ if (flacdec->start_segment) {
+ gst_event_unref (flacdec->start_segment);
+ flacdec->start_segment = NULL;
+ }
+ gst_buffer_replace (&flacdec->pending, NULL);
+ flacdec->pending_samples = 0;
+
+ /* save a segment copy until we know the seek worked. The idea is that
+ * when the seek fails, we want to restore with what we were doing. */
+ segment = flacdec->segment;
+
+ /* update the segment with the seek values, last_stop will contain the new
+ * position we should seek to */
+ gst_segment_set_seek (&flacdec->segment, rate, GST_FORMAT_DEFAULT,
+ seek_flags, start_type, start, stop_type, stop, &only_update);
+
+ GST_DEBUG_OBJECT (flacdec,
+ "configured segment: [%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT
+ "] = [%" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "]",
+ flacdec->segment.start, flacdec->segment.stop,
+ GST_TIME_ARGS (flacdec->segment.start * GST_SECOND /
+ flacdec->sample_rate),
+ GST_TIME_ARGS (flacdec->segment.stop * GST_SECOND /
+ flacdec->sample_rate));
+
+ GST_DEBUG_OBJECT (flacdec, "performing seek to sample %" G_GINT64_FORMAT,
+ flacdec->segment.last_stop);
+
+ /* flush sinkpad again because we need to pull and push buffers while doing
+ * the seek */
+ if (flush) {
+ GST_DEBUG_OBJECT (flacdec, "flushing stop");
+ gst_pad_push_event (flacdec->sinkpad, gst_event_new_flush_stop ());
+ gst_pad_push_event (flacdec->srcpad, gst_event_new_flush_stop ());
+ }
+
+ /* mark ourselves as seeking because the above lines will trigger some
+ * callbacks that need to behave differently when seeking */
+ flacdec->seeking = TRUE;
+
+ if (!flacdec->eos) {
+ GST_LOG_OBJECT (flacdec, "calling seek_absolute");
+ seek_ok = FLAC__stream_decoder_seek_absolute (flacdec->decoder,
+ flacdec->segment.last_stop);
+ GST_LOG_OBJECT (flacdec, "done with seek_absolute, seek_ok=%d", seek_ok);
+ } else {
+ GST_LOG_OBJECT (flacdec, "not seeking, seeked after end of file");
+ seek_ok = TRUE;
+ }
+
+ flacdec->seeking = FALSE;
+
+ GST_DEBUG_OBJECT (flacdec, "performed seek to sample %" G_GINT64_FORMAT,
+ flacdec->segment.last_stop);
+
+ if (!seek_ok) {
+ GST_WARNING_OBJECT (flacdec, "seek failed");
+ /* seek failed, restore the segment and start streaming again with
+ * the previous segment values */
+ flacdec->segment = segment;
+ } else if (!flush && flacdec->running) {
+ /* we are running the current segment and doing a non-flushing seek,
+ * close the segment first based on the last_stop. */
+ GST_DEBUG_OBJECT (flacdec, "closing running segment %" G_GINT64_FORMAT
+ " to %" G_GINT64_FORMAT, segment.start, segment.last_stop);
+
+ /* convert the old segment values to time to close the old segment */
+ start = gst_util_uint64_scale_int (segment.start, GST_SECOND,
+ flacdec->sample_rate);
+ last_stop =
+ gst_util_uint64_scale_int (segment.last_stop, GST_SECOND,
+ flacdec->sample_rate);
+
+ /* queue the segment for sending in the stream thread, start and time are
+ * always the same. */
+ if (flacdec->close_segment)
+ gst_event_unref (flacdec->close_segment);
+ flacdec->close_segment =
+ gst_event_new_new_segment_full (TRUE,
+ segment.rate, segment.applied_rate, GST_FORMAT_TIME,
+ start, last_stop, start);
+ }
+
+ if (seek_ok) {
+ /* seek succeeded, flacdec->segment contains the new positions */
+ GST_DEBUG_OBJECT (flacdec, "seek successful");
+ }
+
+ /* convert the (new) segment values to time, we will need them to generate the
+ * new segment events. */
+ start = gst_util_uint64_scale_int (flacdec->segment.start, GST_SECOND,
+ flacdec->sample_rate);
+ last_stop = gst_util_uint64_scale_int (flacdec->segment.last_stop, GST_SECOND,
+ flacdec->sample_rate);
+
+ /* for deriving a stop position for the playback segment from the seek
+ * segment, we must take the duration when the stop is not set */
+ if (flacdec->segment.stop != -1)
+ stop = gst_util_uint64_scale_int (flacdec->segment.stop, GST_SECOND,
+ flacdec->sample_rate);
+ else
+ stop = gst_util_uint64_scale_int (flacdec->segment.duration, GST_SECOND,
+ flacdec->sample_rate);
+
+ /* notify start of new segment when we were asked to do so. */
+ if (flacdec->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+ /* last_stop contains the position we start from */
+ gst_element_post_message (GST_ELEMENT (flacdec),
+ gst_message_new_segment_start (GST_OBJECT (flacdec),
+ GST_FORMAT_TIME, last_stop));
+ }
+
+ /* if the seek was ok or (when it failed) we are flushing, we need to send out
+ * a new segment. If we did not flush and the seek failed, we simply do
+ * nothing here and continue where we were. */
+ if (seek_ok || flush) {
+ GST_DEBUG_OBJECT (flacdec, "Creating newsegment from %" GST_TIME_FORMAT
+ " to %" GST_TIME_FORMAT, GST_TIME_ARGS (last_stop),
+ GST_TIME_ARGS (stop));
+ /* now replace the old segment so that we send it in the stream thread the
+ * next time it is scheduled. */
+ if (flacdec->start_segment)
+ gst_event_unref (flacdec->start_segment);
+ flacdec->start_segment =
+ gst_event_new_new_segment_full (FALSE,
+ flacdec->segment.rate, flacdec->segment.applied_rate, GST_FORMAT_TIME,
+ last_stop, stop, last_stop);
+ }
+
+ /* we'll generate a discont on the next buffer */
+ flacdec->discont = TRUE;
+ /* the task is running again now */
+ flacdec->running = TRUE;
+ gst_pad_start_task (flacdec->sinkpad,
+ (GstTaskFunction) gst_flac_dec_loop, flacdec->sinkpad);
+
+ GST_PAD_STREAM_UNLOCK (flacdec->sinkpad);
+
+ return seek_ok;
+}
+
+static gboolean
+gst_flac_dec_src_event (GstPad * pad, GstEvent * event)
+{
+ gboolean res = TRUE;
+ GstFlacDec *flacdec;
+
+ flacdec = GST_FLAC_DEC (gst_pad_get_parent (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:{
+ GST_DEBUG_OBJECT (flacdec, "received seek event %p", event);
+ /* first, see if we're before a demuxer that
+ * might handle the seek for us */
+ gst_event_ref (event);
+ res = gst_pad_event_default (pad, event);
+ /* if not, try to handle it ourselves */
+ if (!res) {
+ GST_DEBUG_OBJECT (flacdec, "default failed, handling ourselves");
+ res = gst_flac_dec_handle_seek_event (flacdec, event);
+ }
+ gst_event_unref (event);
+ break;
+ }
+ default:
+ res = gst_pad_event_default (pad, event);
+ break;
+ }
+
+ gst_object_unref (flacdec);
+
+ return res;
+}
+
+static gboolean
+gst_flac_dec_sink_activate (GstPad * sinkpad)
+{
+ if (gst_pad_check_pull_range (sinkpad))
+ return gst_pad_activate_pull (sinkpad, TRUE);
+
+ return gst_pad_activate_push (sinkpad, TRUE);
+}
+
+static gboolean
+gst_flac_dec_sink_activate_push (GstPad * sinkpad, gboolean active)
+{
+ GstFlacDec *dec = GST_FLAC_DEC (GST_OBJECT_PARENT (sinkpad));
+
+ if (active) {
+ gst_flac_dec_setup_decoder (dec);
+ dec->streaming = TRUE;
+ dec->got_headers = FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+gst_flac_dec_sink_activate_pull (GstPad * sinkpad, gboolean active)
+{
+ gboolean res;
+
+ if (active) {
+ GstFlacDec *flacdec;
+
+ flacdec = GST_FLAC_DEC (GST_PAD_PARENT (sinkpad));
+
+ flacdec->offset = 0;
+ gst_flac_dec_setup_decoder (flacdec);
+ flacdec->running = TRUE;
+ flacdec->streaming = FALSE;
+
+ res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flac_dec_loop,
+ sinkpad);
+ } else {
+ res = gst_pad_stop_task (sinkpad);
+ }
+ return res;
+}
+
+static GstStateChangeReturn
+gst_flac_dec_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstFlacDec *flacdec = GST_FLAC_DEC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ flacdec->eos = FALSE;
+ flacdec->seeking = FALSE;
+ flacdec->channels = 0;
+ flacdec->depth = 0;
+ flacdec->width = 0;
+ flacdec->sample_rate = 0;
+ gst_segment_init (&flacdec->segment, GST_FORMAT_DEFAULT);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_segment_init (&flacdec->segment, GST_FORMAT_UNDEFINED);
+ gst_flac_dec_reset_decoders (flacdec);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/flac/gstflacdec.h b/ext/flac/gstflacdec.h
new file mode 100644
index 0000000..835bdbd
--- /dev/null
+++ b/ext/flac/gstflacdec.h
@@ -0,0 +1,101 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_FLAC_DEC_H__
+#define __GST_FLAC_DEC_H__
+
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+#include <FLAC/all.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_FLAC_DEC gst_flac_dec_get_type()
+#define GST_FLAC_DEC(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, GST_TYPE_FLAC_DEC, GstFlacDec)
+#define GST_FLAC_DEC_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, GST_TYPE_FLAC_DEC, GstFlacDecClass)
+#define GST_IS_FLAC_DEC(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, GST_TYPE_FLAC_DEC)
+#define GST_IS_FLAC_DEC_CLASS(klass) G_TYPE_CHECK_CLASS_TYPE(klass, GST_TYPE_FLAC_DEC)
+
+typedef struct _GstFlacDec GstFlacDec;
+typedef struct _GstFlacDecClass GstFlacDecClass;
+
+struct _GstFlacDec {
+ GstElement element;
+
+ /* < private > */
+
+ FLAC__StreamDecoder *decoder;
+ GstAdapter *adapter;
+ gboolean framed;
+ gboolean streaming;
+
+ gboolean got_headers; /* if we've parsed the headers (unframed push mode only) */
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ gboolean init;
+
+ guint64 offset; /* current byte offset of input */
+
+ gboolean seeking; /* set to TRUE while seeking to make sure we
+ * don't push any buffers in the write callback
+ * until we are actually at the new position */
+
+ gboolean eos; /* set to TRUE if seeked after the end of file */
+
+ GstSegment segment; /* the currently configured segment, in
+ * samples/audio frames (DEFAULT format) */
+ gboolean running;
+ gboolean discont;
+ GstBuffer *pending; /* pending buffer, produced in seek */
+ guint pending_samples;
+ GstEvent *close_segment;
+ GstEvent *start_segment;
+ GstTagList *tags;
+
+ GstFlowReturn pull_flow; /* last flow from pull_range */ /* STREAM_LOCK */
+
+ GstFlowReturn last_flow; /* the last flow return received from either
+ * gst_pad_push or gst_pad_buffer_alloc */
+
+ gint channels;
+ gint depth;
+ gint width;
+ gint sample_rate;
+
+ /* from the stream info, needed for scanning */
+ guint16 min_blocksize;
+ guint16 max_blocksize;
+
+ gint64 cur_granulepos; /* only used in framed mode (flac-in-ogg) */
+};
+
+struct _GstFlacDecClass {
+ GstElementClass parent_class;
+};
+
+GType gst_flac_dec_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_FLAC_DEC_H__ */
diff --git a/ext/flac/gstflacenc.c b/ext/flac/gstflacenc.c
new file mode 100644
index 0000000..6a7e1c0
--- /dev/null
+++ b/ext/flac/gstflacenc.c
@@ -0,0 +1,1399 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:element-flacenc
+ * @see_also: #GstFlacDec
+ *
+ * flacenc encodes FLAC streams.
+ * <ulink url="http://flac.sourceforge.net/">FLAC</ulink>
+ * is a Free Lossless Audio Codec.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch audiotestsrc num-buffers=100 ! flacenc ! filesink location=beep.flac
+ * ]|
+ * </refsect2>
+ */
+
+/* TODO: - We currently don't handle discontinuities in the stream in a useful
+ * way and instead rely on the developer plugging in audiorate if
+ * the stream contains discontinuities.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include <gstflacenc.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/multichannel.h>
+#include <gst/tag/tag.h>
+#include <gst/gsttagsetter.h>
+
+/* Taken from http://flac.sourceforge.net/format.html#frame_header */
+static const GstAudioChannelPosition channel_positions[8][8] = {
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_MONO},
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
+ /* FIXME: 7/8 channel layouts are not defined in the FLAC specs */
+ {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE,
+ GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
+};
+
+#define FLAC_SINK_CAPS \
+ "audio/x-raw-int, " \
+ "endianness = (int) BYTE_ORDER, " \
+ "signed = (boolean) TRUE, " \
+ "width = (int) 8, " \
+ "depth = (int) 8, " \
+ "rate = (int) [ 1, 655350 ], " \
+ "channels = (int) [ 1, 8 ]; " \
+ "audio/x-raw-int, " \
+ "endianness = (int) BYTE_ORDER, " \
+ "signed = (boolean) TRUE, " \
+ "width = (int) 16, " \
+ "depth = (int) { 12, 16 }, " \
+ "rate = (int) [ 1, 655350 ], " \
+ "channels = (int) [ 1, 8 ]; " \
+ "audio/x-raw-int, " \
+ "endianness = (int) BYTE_ORDER, " \
+ "signed = (boolean) TRUE, " \
+ "width = (int) 32, " \
+ "depth = (int) { 20, 24 }, " \
+ "rate = (int) [ 1, 655350 ], " \
+ "channels = (int) [ 1, 8 ]"
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-flac")
+ );
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (FLAC_SINK_CAPS)
+ );
+
+enum
+{
+ PROP_0,
+ PROP_QUALITY,
+ PROP_STREAMABLE_SUBSET,
+ PROP_MID_SIDE_STEREO,
+ PROP_LOOSE_MID_SIDE_STEREO,
+ PROP_BLOCKSIZE,
+ PROP_MAX_LPC_ORDER,
+ PROP_QLP_COEFF_PRECISION,
+ PROP_QLP_COEFF_PREC_SEARCH,
+ PROP_ESCAPE_CODING,
+ PROP_EXHAUSTIVE_MODEL_SEARCH,
+ PROP_MIN_RESIDUAL_PARTITION_ORDER,
+ PROP_MAX_RESIDUAL_PARTITION_ORDER,
+ PROP_RICE_PARAMETER_SEARCH_DIST,
+ PROP_PADDING,
+ PROP_SEEKPOINTS
+};
+
+GST_DEBUG_CATEGORY_STATIC (flacenc_debug);
+#define GST_CAT_DEFAULT flacenc_debug
+
+
+#define _do_init(type) \
+ G_STMT_START{ \
+ static const GInterfaceInfo tag_setter_info = { \
+ NULL, \
+ NULL, \
+ NULL \
+ }; \
+ g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, \
+ &tag_setter_info); \
+ }G_STMT_END
+
+GST_BOILERPLATE_FULL (GstFlacEnc, gst_flac_enc, GstAudioEncoder,
+ GST_TYPE_AUDIO_ENCODER, _do_init);
+
+static gboolean gst_flac_enc_start (GstAudioEncoder * enc);
+static gboolean gst_flac_enc_stop (GstAudioEncoder * enc);
+static gboolean gst_flac_enc_set_format (GstAudioEncoder * enc,
+ GstAudioInfo * info);
+static GstFlowReturn gst_flac_enc_handle_frame (GstAudioEncoder * enc,
+ GstBuffer * in_buf);
+static GstCaps *gst_flac_enc_getcaps (GstAudioEncoder * enc);
+static gboolean gst_flac_enc_sink_event (GstAudioEncoder * enc,
+ GstEvent * event);
+
+static void gst_flac_enc_finalize (GObject * object);
+
+static gboolean gst_flac_enc_update_quality (GstFlacEnc * flacenc,
+ gint quality);
+static void gst_flac_enc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_flac_enc_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static FLAC__StreamEncoderWriteStatus
+gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
+ const FLAC__byte buffer[], size_t bytes,
+ unsigned samples, unsigned current_frame, void *client_data);
+static FLAC__StreamEncoderSeekStatus
+gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
+ FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamEncoderTellStatus
+gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
+ FLAC__uint64 * absolute_byte_offset, void *client_data);
+
+typedef struct
+{
+ gboolean exhaustive_model_search;
+ gboolean escape_coding;
+ gboolean mid_side;
+ gboolean loose_mid_side;
+ guint qlp_coeff_precision;
+ gboolean qlp_coeff_prec_search;
+ guint min_residual_partition_order;
+ guint max_residual_partition_order;
+ guint rice_parameter_search_dist;
+ guint max_lpc_order;
+ guint blocksize;
+}
+GstFlacEncParams;
+
+static const GstFlacEncParams flacenc_params[] = {
+ {FALSE, FALSE, FALSE, FALSE, 0, FALSE, 2, 2, 0, 0, 1152},
+ {FALSE, FALSE, TRUE, TRUE, 0, FALSE, 2, 2, 0, 0, 1152},
+ {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 3, 0, 0, 1152},
+ {FALSE, FALSE, FALSE, FALSE, 0, FALSE, 3, 3, 0, 6, 4608},
+ {FALSE, FALSE, TRUE, TRUE, 0, FALSE, 3, 3, 0, 8, 4608},
+ {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 3, 3, 0, 8, 4608},
+ {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 4, 0, 8, 4608},
+ {TRUE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0, 8, 4608},
+ {TRUE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0, 12, 4608},
+ {TRUE, TRUE, TRUE, FALSE, 0, FALSE, 0, 16, 0, 32, 4608},
+};
+
+#define DEFAULT_QUALITY 5
+#define DEFAULT_PADDING 0
+#define DEFAULT_SEEKPOINTS 0
+
+#define GST_TYPE_FLAC_ENC_QUALITY (gst_flac_enc_quality_get_type ())
+static GType
+gst_flac_enc_quality_get_type (void)
+{
+ static GType qtype = 0;
+
+ if (qtype == 0) {
+ static const GEnumValue values[] = {
+ {0, "0 - Fastest compression", "0"},
+ {1, "1", "1"},
+ {2, "2", "2"},
+ {3, "3", "3"},
+ {4, "4", "4"},
+ {5, "5 - Default", "5"},
+ {6, "6", "6"},
+ {7, "7", "7"},
+ {8, "8 - Highest compression", "8"},
+ {9, "9 - Insane", "9"},
+ {0, NULL, NULL}
+ };
+
+ qtype = g_enum_register_static ("GstFlacEncQuality", values);
+ }
+ return qtype;
+}
+
+static void
+gst_flac_enc_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class, &src_factory);
+ gst_element_class_add_static_pad_template (element_class, &sink_factory);
+
+ gst_element_class_set_details_simple (element_class, "FLAC audio encoder",
+ "Codec/Encoder/Audio",
+ "Encodes audio with the FLAC lossless audio encoder",
+ "Wim Taymans <wim.taymans@chello.be>");
+
+ GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0,
+ "Flac encoding element");
+}
+
+static void
+gst_flac_enc_class_init (GstFlacEncClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstAudioEncoderClass *base_class;
+
+ gobject_class = (GObjectClass *) klass;
+ base_class = (GstAudioEncoderClass *) (klass);
+
+ gobject_class->set_property = gst_flac_enc_set_property;
+ gobject_class->get_property = gst_flac_enc_get_property;
+ gobject_class->finalize = gst_flac_enc_finalize;
+
+ base_class->start = GST_DEBUG_FUNCPTR (gst_flac_enc_start);
+ base_class->stop = GST_DEBUG_FUNCPTR (gst_flac_enc_stop);
+ base_class->set_format = GST_DEBUG_FUNCPTR (gst_flac_enc_set_format);
+ base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_flac_enc_handle_frame);
+ base_class->getcaps = GST_DEBUG_FUNCPTR (gst_flac_enc_getcaps);
+ base_class->event = GST_DEBUG_FUNCPTR (gst_flac_enc_sink_event);
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
+ g_param_spec_enum ("quality",
+ "Quality",
+ "Speed versus compression tradeoff",
+ GST_TYPE_FLAC_ENC_QUALITY, DEFAULT_QUALITY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_STREAMABLE_SUBSET, g_param_spec_boolean ("streamable-subset",
+ "Streamable subset",
+ "true to limit encoder to generating a Subset stream, else false",
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MID_SIDE_STEREO,
+ g_param_spec_boolean ("mid-side-stereo", "Do mid side stereo",
+ "Do mid side stereo (only for stereo input)",
+ flacenc_params[DEFAULT_QUALITY].mid_side,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_LOOSE_MID_SIDE_STEREO, g_param_spec_boolean ("loose-mid-side-stereo",
+ "Loose mid side stereo", "Loose mid side stereo",
+ flacenc_params[DEFAULT_QUALITY].loose_mid_side,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BLOCKSIZE,
+ g_param_spec_uint ("blocksize", "Blocksize", "Blocksize in samples",
+ FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE,
+ flacenc_params[DEFAULT_QUALITY].blocksize,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_LPC_ORDER,
+ g_param_spec_uint ("max-lpc-order", "Max LPC order",
+ "Max LPC order; 0 => use only fixed predictors", 0,
+ FLAC__MAX_LPC_ORDER, flacenc_params[DEFAULT_QUALITY].max_lpc_order,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_QLP_COEFF_PRECISION, g_param_spec_uint ("qlp-coeff-precision",
+ "QLP coefficients precision",
+ "Precision in bits of quantized linear-predictor coefficients; 0 = automatic",
+ 0, 32, flacenc_params[DEFAULT_QUALITY].qlp_coeff_precision,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_QLP_COEFF_PREC_SEARCH, g_param_spec_boolean ("qlp-coeff-prec-search",
+ "Do QLP coefficients precision search",
+ "false = use qlp_coeff_precision, "
+ "true = search around qlp_coeff_precision, take best",
+ flacenc_params[DEFAULT_QUALITY].qlp_coeff_prec_search,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ESCAPE_CODING,
+ g_param_spec_boolean ("escape-coding", "Do Escape coding",
+ "search for escape codes in the entropy coding stage "
+ "for slightly better compression",
+ flacenc_params[DEFAULT_QUALITY].escape_coding,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_EXHAUSTIVE_MODEL_SEARCH,
+ g_param_spec_boolean ("exhaustive-model-search",
+ "Do exhaustive model search",
+ "do exhaustive search of LP coefficient quantization (expensive!)",
+ flacenc_params[DEFAULT_QUALITY].exhaustive_model_search,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_MIN_RESIDUAL_PARTITION_ORDER,
+ g_param_spec_uint ("min-residual-partition-order",
+ "Min residual partition order",
+ "Min residual partition order (above 4 doesn't usually help much)", 0,
+ 16, flacenc_params[DEFAULT_QUALITY].min_residual_partition_order,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_MAX_RESIDUAL_PARTITION_ORDER,
+ g_param_spec_uint ("max-residual-partition-order",
+ "Max residual partition order",
+ "Max residual partition order (above 4 doesn't usually help much)", 0,
+ 16, flacenc_params[DEFAULT_QUALITY].max_residual_partition_order,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_RICE_PARAMETER_SEARCH_DIST,
+ g_param_spec_uint ("rice-parameter-search-dist",
+ "rice_parameter_search_dist",
+ "0 = try only calc'd parameter k; else try all [k-dist..k+dist] "
+ "parameters, use best", 0, FLAC__MAX_RICE_PARTITION_ORDER,
+ flacenc_params[DEFAULT_QUALITY].rice_parameter_search_dist,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstFlacEnc:padding
+ *
+ * Write a PADDING block with this length in bytes
+ *
+ * Since: 0.10.16
+ **/
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_PADDING,
+ g_param_spec_uint ("padding",
+ "Padding",
+ "Write a PADDING block with this length in bytes", 0, G_MAXUINT,
+ DEFAULT_PADDING,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstFlacEnc:seekpoints
+ *
+ * Write a SEEKTABLE block with a specific number of seekpoints
+ * or with a specific interval spacing.
+ *
+ * Since: 0.10.18
+ **/
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_SEEKPOINTS,
+ g_param_spec_int ("seekpoints",
+ "Seekpoints",
+ "Add SEEKTABLE metadata (if > 0, number of entries, if < 0, interval in sec)",
+ -G_MAXINT, G_MAXINT,
+ DEFAULT_SEEKPOINTS,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_flac_enc_init (GstFlacEnc * flacenc, GstFlacEncClass * klass)
+{
+ GstAudioEncoder *enc = GST_AUDIO_ENCODER (flacenc);
+
+ flacenc->encoder = FLAC__stream_encoder_new ();
+ gst_flac_enc_update_quality (flacenc, DEFAULT_QUALITY);
+
+ /* arrange granulepos marking (and required perfect ts) */
+ gst_audio_encoder_set_mark_granule (enc, TRUE);
+ gst_audio_encoder_set_perfect_timestamp (enc, TRUE);
+}
+
+static void
+gst_flac_enc_finalize (GObject * object)
+{
+ GstFlacEnc *flacenc = GST_FLAC_ENC (object);
+
+ FLAC__stream_encoder_delete (flacenc->encoder);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_flac_enc_start (GstAudioEncoder * enc)
+{
+ GstFlacEnc *flacenc = GST_FLAC_ENC (enc);
+
+ GST_DEBUG_OBJECT (enc, "start");
+ flacenc->stopped = TRUE;
+ flacenc->got_headers = FALSE;
+ flacenc->last_flow = GST_FLOW_OK;
+ flacenc->offset = 0;
+ flacenc->channels = 0;
+ flacenc->depth = 0;
+ flacenc->sample_rate = 0;
+ flacenc->eos = FALSE;
+ flacenc->tags = gst_tag_list_new ();
+
+ return TRUE;
+}
+
+static gboolean
+gst_flac_enc_stop (GstAudioEncoder * enc)
+{
+ GstFlacEnc *flacenc = GST_FLAC_ENC (enc);
+
+ GST_DEBUG_OBJECT (enc, "stop");
+ gst_tag_list_free (flacenc->tags);
+ flacenc->tags = NULL;
+ if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
+ FLAC__STREAM_ENCODER_UNINITIALIZED) {
+ flacenc->stopped = TRUE;
+ FLAC__stream_encoder_finish (flacenc->encoder);
+ }
+ if (flacenc->meta) {
+ FLAC__metadata_object_delete (flacenc->meta[0]);
+
+ if (flacenc->meta[1])
+ FLAC__metadata_object_delete (flacenc->meta[1]);
+
+ if (flacenc->meta[2])
+ FLAC__metadata_object_delete (flacenc->meta[2]);
+
+ g_free (flacenc->meta);
+ flacenc->meta = NULL;
+ }
+ g_list_foreach (flacenc->headers, (GFunc) gst_mini_object_unref, NULL);
+ g_list_free (flacenc->headers);
+ flacenc->headers = NULL;
+
+ gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
+
+ return TRUE;
+}
+
+static void
+add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
+{
+ GList *comments;
+ GList *it;
+ GstFlacEnc *flacenc = GST_FLAC_ENC (user_data);
+
+ /* IMAGE and PREVIEW_IMAGE tags are already written
+ * differently, no need to store them inside the
+ * vorbiscomments too */
+ if (strcmp (tag, GST_TAG_IMAGE) == 0
+ || strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0)
+ return;
+
+ comments = gst_tag_to_vorbis_comments (list, tag);
+ for (it = comments; it != NULL; it = it->next) {
+ FLAC__StreamMetadata_VorbisComment_Entry commment_entry;
+
+ commment_entry.length = strlen (it->data);
+ commment_entry.entry = it->data;
+ FLAC__metadata_object_vorbiscomment_insert_comment (flacenc->meta[0],
+ flacenc->meta[0]->data.vorbis_comment.num_comments,
+ commment_entry, TRUE);
+ g_free (it->data);
+ }
+ g_list_free (comments);
+}
+
+static void
+gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples)
+{
+ const GstTagList *user_tags;
+ GstTagList *copy;
+ gint entries = 1;
+ gint n_images, n_preview_images;
+
+ g_return_if_fail (flacenc != NULL);
+ user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (flacenc));
+ if ((flacenc->tags == NULL) && (user_tags == NULL)) {
+ return;
+ }
+ copy = gst_tag_list_merge (user_tags, flacenc->tags,
+ gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (flacenc)));
+ n_images = gst_tag_list_get_tag_size (copy, GST_TAG_IMAGE);
+ n_preview_images = gst_tag_list_get_tag_size (copy, GST_TAG_PREVIEW_IMAGE);
+
+ flacenc->meta =
+ g_new0 (FLAC__StreamMetadata *, 3 + n_images + n_preview_images);
+
+ flacenc->meta[0] =
+ FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ gst_tag_list_foreach (copy, add_one_tag, flacenc);
+
+ if (n_images + n_preview_images > 0) {
+ GstBuffer *buffer;
+ GstCaps *caps;
+ GstStructure *structure;
+ GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
+ gint i;
+
+ for (i = 0; i < n_images + n_preview_images; i++) {
+ if (i < n_images) {
+ if (!gst_tag_list_get_buffer_index (copy, GST_TAG_IMAGE, i, &buffer))
+ continue;
+ } else {
+ if (!gst_tag_list_get_buffer_index (copy, GST_TAG_PREVIEW_IMAGE,
+ i - n_images, &buffer))
+ continue;
+ }
+
+ flacenc->meta[entries] =
+ FLAC__metadata_object_new (FLAC__METADATA_TYPE_PICTURE);
+
+ caps = gst_buffer_get_caps (buffer);
+ structure = gst_caps_get_structure (caps, 0);
+
+ gst_structure_get (structure, "image-type", GST_TYPE_TAG_IMAGE_TYPE,
+ &image_type, NULL);
+ /* Convert to ID3v2 APIC image type */
+ if (image_type == GST_TAG_IMAGE_TYPE_NONE)
+ image_type = (i < n_images) ? 0x00 : 0x01;
+ else
+ image_type = image_type + 2;
+
+ FLAC__metadata_object_picture_set_data (flacenc->meta[entries],
+ GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), TRUE);
+ /* FIXME: There's no way to set the picture type in libFLAC */
+ flacenc->meta[entries]->data.picture.type = image_type;
+ FLAC__metadata_object_picture_set_mime_type (flacenc->meta[entries],
+ (char *) gst_structure_get_name (structure), TRUE);
+
+ gst_caps_unref (caps);
+ gst_buffer_unref (buffer);
+ entries++;
+ }
+ }
+
+ if (flacenc->seekpoints && total_samples != GST_CLOCK_TIME_NONE) {
+ gboolean res;
+ guint samples;
+
+ flacenc->meta[entries] =
+ FLAC__metadata_object_new (FLAC__METADATA_TYPE_SEEKTABLE);
+ if (flacenc->seekpoints > 0) {
+ res =
+ FLAC__metadata_object_seektable_template_append_spaced_points
+ (flacenc->meta[entries], flacenc->seekpoints, total_samples);
+ } else {
+ samples = -flacenc->seekpoints * flacenc->sample_rate;
+ res =
+ FLAC__metadata_object_seektable_template_append_spaced_points_by_samples
+ (flacenc->meta[entries], samples, total_samples);
+ }
+ if (!res) {
+ GST_DEBUG_OBJECT (flacenc, "adding seekpoint template %d failed",
+ flacenc->seekpoints);
+ FLAC__metadata_object_delete (flacenc->meta[1]);
+ flacenc->meta[entries] = NULL;
+ } else {
+ entries++;
+ }
+ } else if (flacenc->seekpoints && total_samples == GST_CLOCK_TIME_NONE) {
+ GST_WARNING_OBJECT (flacenc, "total time unknown; can not add seekpoints");
+ }
+
+ if (flacenc->padding > 0) {
+ flacenc->meta[entries] =
+ FLAC__metadata_object_new (FLAC__METADATA_TYPE_PADDING);
+ flacenc->meta[entries]->length = flacenc->padding;
+ entries++;
+ }
+
+ if (FLAC__stream_encoder_set_metadata (flacenc->encoder,
+ flacenc->meta, entries) != true)
+ g_warning ("Dude, i'm already initialized!");
+
+ gst_tag_list_free (copy);
+}
+
+static void
+gst_flac_enc_caps_append_structure_with_widths (GstCaps * caps,
+ GstStructure * s)
+{
+ GstStructure *tmp;
+ GValue list = { 0, };
+ GValue depth = { 0, };
+
+
+ tmp = gst_structure_copy (s);
+ gst_structure_set (tmp, "width", G_TYPE_INT, 8, "depth", G_TYPE_INT, 8, NULL);
+ gst_caps_append_structure (caps, tmp);
+
+ tmp = gst_structure_copy (s);
+
+ g_value_init (&depth, G_TYPE_INT);
+ g_value_init (&list, GST_TYPE_LIST);
+ g_value_set_int (&depth, 12);
+ gst_value_list_append_value (&list, &depth);
+ g_value_set_int (&depth, 16);
+ gst_value_list_append_value (&list, &depth);
+
+ gst_structure_set (tmp, "width", G_TYPE_INT, 16, NULL);
+ gst_structure_set_value (tmp, "depth", &list);
+ gst_caps_append_structure (caps, tmp);
+
+ g_value_reset (&list);
+
+ tmp = s;
+
+ g_value_set_int (&depth, 20);
+ gst_value_list_append_value (&list, &depth);
+ g_value_set_int (&depth, 24);
+ gst_value_list_append_value (&list, &depth);
+
+ gst_structure_set (tmp, "width", G_TYPE_INT, 32, NULL);
+ gst_structure_set_value (tmp, "depth", &list);
+ gst_caps_append_structure (caps, tmp);
+
+ g_value_unset (&list);
+ g_value_unset (&depth);
+}
+
+static GstCaps *
+gst_flac_enc_getcaps (GstAudioEncoder * enc)
+{
+ GstCaps *ret = NULL, *caps = NULL;
+ GstPad *pad;
+
+ pad = GST_AUDIO_ENCODER_SINK_PAD (enc);
+
+ GST_OBJECT_LOCK (pad);
+
+ if (GST_PAD_CAPS (pad)) {
+ ret = gst_caps_ref (GST_PAD_CAPS (pad));
+ } else {
+ gint i, c;
+
+ ret = gst_caps_new_empty ();
+
+ gst_flac_enc_caps_append_structure_with_widths (ret,
+ gst_structure_new ("audio/x-raw-int",
+ "endianness", G_TYPE_INT, G_BYTE_ORDER,
+ "signed", G_TYPE_BOOLEAN, TRUE,
+ "rate", GST_TYPE_INT_RANGE, 1, 655350,
+ "channels", GST_TYPE_INT_RANGE, 1, 2, NULL));
+
+ for (i = 3; i <= 8; i++) {
+ GValue positions = { 0, };
+ GValue pos = { 0, };
+ GstStructure *s;
+
+ g_value_init (&positions, GST_TYPE_ARRAY);
+ g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
+
+ for (c = 0; c < i; c++) {
+ g_value_set_enum (&pos, channel_positions[i - 1][c]);
+ gst_value_array_append_value (&positions, &pos);
+ }
+ g_value_unset (&pos);
+
+ s = gst_structure_new ("audio/x-raw-int",
+ "endianness", G_TYPE_INT, G_BYTE_ORDER,
+ "signed", G_TYPE_BOOLEAN, TRUE,
+ "rate", GST_TYPE_INT_RANGE, 1, 655350,
+ "channels", G_TYPE_INT, i, NULL);
+ gst_structure_set_value (s, "channel-positions", &positions);
+ g_value_unset (&positions);
+
+ gst_flac_enc_caps_append_structure_with_widths (ret, s);
+ }
+ }
+
+ GST_OBJECT_UNLOCK (pad);
+
+ GST_DEBUG_OBJECT (pad, "Return caps %" GST_PTR_FORMAT, ret);
+
+ caps = gst_audio_encoder_proxy_getcaps (enc, ret);
+ gst_caps_unref (ret);
+
+ return caps;
+}
+
+static guint64
+gst_flac_enc_query_peer_total_samples (GstFlacEnc * flacenc, GstPad * pad)
+{
+ GstFormat fmt = GST_FORMAT_DEFAULT;
+ gint64 duration;
+
+ GST_DEBUG_OBJECT (flacenc, "querying peer for DEFAULT format duration");
+ if (gst_pad_query_peer_duration (pad, &fmt, &duration)
+ && fmt == GST_FORMAT_DEFAULT && duration != GST_CLOCK_TIME_NONE)
+ goto done;
+
+ fmt = GST_FORMAT_TIME;
+ GST_DEBUG_OBJECT (flacenc, "querying peer for TIME format duration");
+
+ if (gst_pad_query_peer_duration (pad, &fmt, &duration) &&
+ fmt == GST_FORMAT_TIME && duration != GST_CLOCK_TIME_NONE) {
+ GST_DEBUG_OBJECT (flacenc, "peer reported duration %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (duration));
+ duration = GST_CLOCK_TIME_TO_FRAMES (duration, flacenc->sample_rate);
+
+ goto done;
+ }
+
+ GST_DEBUG_OBJECT (flacenc, "Upstream reported no total samples");
+ return GST_CLOCK_TIME_NONE;
+
+done:
+ GST_DEBUG_OBJECT (flacenc,
+ "Upstream reported %" G_GUINT64_FORMAT " total samples", duration);
+
+ return duration;
+}
+
+static gboolean
+gst_flac_enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
+{
+ GstFlacEnc *flacenc;
+ guint64 total_samples = GST_CLOCK_TIME_NONE;
+ FLAC__StreamEncoderInitStatus init_status;
+ GstCaps *caps;
+
+ flacenc = GST_FLAC_ENC (enc);
+
+ /* if configured again, means something changed, can't handle that */
+ if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
+ FLAC__STREAM_ENCODER_UNINITIALIZED)
+ goto encoder_already_initialized;
+
+ flacenc->channels = GST_AUDIO_INFO_CHANNELS (info);
+ flacenc->width = GST_AUDIO_INFO_WIDTH (info);
+ flacenc->depth = GST_AUDIO_INFO_DEPTH (info);
+ flacenc->sample_rate = GST_AUDIO_INFO_RATE (info);
+
+ caps = gst_caps_new_simple ("audio/x-flac",
+ "channels", G_TYPE_INT, flacenc->channels,
+ "rate", G_TYPE_INT, flacenc->sample_rate, NULL);
+
+ if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps))
+ goto setting_src_caps_failed;
+
+ gst_caps_unref (caps);
+
+ total_samples = gst_flac_enc_query_peer_total_samples (flacenc,
+ GST_AUDIO_ENCODER_SINK_PAD (enc));
+
+ FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder, flacenc->depth);
+ FLAC__stream_encoder_set_sample_rate (flacenc->encoder, flacenc->sample_rate);
+ FLAC__stream_encoder_set_channels (flacenc->encoder, flacenc->channels);
+
+ if (total_samples != GST_CLOCK_TIME_NONE)
+ FLAC__stream_encoder_set_total_samples_estimate (flacenc->encoder,
+ MIN (total_samples, G_GUINT64_CONSTANT (0x0FFFFFFFFF)));
+
+ gst_flac_enc_set_metadata (flacenc, total_samples);
+
+ /* callbacks clear to go now;
+ * write callbacks receives headers during init */
+ flacenc->stopped = FALSE;
+
+ init_status = FLAC__stream_encoder_init_stream (flacenc->encoder,
+ gst_flac_enc_write_callback, gst_flac_enc_seek_callback,
+ gst_flac_enc_tell_callback, NULL, flacenc);
+ if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+ goto failed_to_initialize;
+
+ /* no special feedback to base class; should provide all available samples */
+
+ return TRUE;
+
+encoder_already_initialized:
+ {
+ g_warning ("flac already initialized -- fixme allow this");
+ gst_object_unref (flacenc);
+ return FALSE;
+ }
+setting_src_caps_failed:
+ {
+ GST_DEBUG_OBJECT (flacenc,
+ "Couldn't set caps on source pad: %" GST_PTR_FORMAT, caps);
+ gst_caps_unref (caps);
+ gst_object_unref (flacenc);
+ return FALSE;
+ }
+failed_to_initialize:
+ {
+ GST_ELEMENT_ERROR (flacenc, LIBRARY, INIT, (NULL),
+ ("could not initialize encoder (wrong parameters?)"));
+ gst_object_unref (flacenc);
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
+{
+ flacenc->quality = quality;
+
+#define DO_UPDATE(name, val, str) \
+ G_STMT_START { \
+ if (FLAC__stream_encoder_get_##name (flacenc->encoder) != \
+ flacenc_params[quality].val) { \
+ FLAC__stream_encoder_set_##name (flacenc->encoder, \
+ flacenc_params[quality].val); \
+ g_object_notify (G_OBJECT (flacenc), str); \
+ } \
+ } G_STMT_END
+
+ g_object_freeze_notify (G_OBJECT (flacenc));
+
+ if (flacenc->channels == 2 || flacenc->channels == 0) {
+ DO_UPDATE (do_mid_side_stereo, mid_side, "mid_side_stereo");
+ DO_UPDATE (loose_mid_side_stereo, loose_mid_side, "loose_mid_side");
+ }
+
+ DO_UPDATE (blocksize, blocksize, "blocksize");
+ DO_UPDATE (max_lpc_order, max_lpc_order, "max_lpc_order");
+ DO_UPDATE (qlp_coeff_precision, qlp_coeff_precision, "qlp_coeff_precision");
+ DO_UPDATE (do_qlp_coeff_prec_search, qlp_coeff_prec_search,
+ "qlp_coeff_prec_search");
+ DO_UPDATE (do_escape_coding, escape_coding, "escape_coding");
+ DO_UPDATE (do_exhaustive_model_search, exhaustive_model_search,
+ "exhaustive_model_search");
+ DO_UPDATE (min_residual_partition_order, min_residual_partition_order,
+ "min_residual_partition_order");
+ DO_UPDATE (max_residual_partition_order, max_residual_partition_order,
+ "max_residual_partition_order");
+ DO_UPDATE (rice_parameter_search_dist, rice_parameter_search_dist,
+ "rice_parameter_search_dist");
+
+#undef DO_UPDATE
+
+ g_object_thaw_notify (G_OBJECT (flacenc));
+
+ return TRUE;
+}
+
+static FLAC__StreamEncoderSeekStatus
+gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
+ FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+ GstFlacEnc *flacenc;
+ GstPad *peerpad;
+
+ flacenc = GST_FLAC_ENC (client_data);
+
+ if (flacenc->stopped)
+ return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+
+ if ((peerpad = gst_pad_get_peer (GST_AUDIO_ENCODER_SRC_PAD (flacenc)))) {
+ GstEvent *event = gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES,
+ absolute_byte_offset, GST_BUFFER_OFFSET_NONE, 0);
+ gboolean ret = gst_pad_send_event (peerpad, event);
+
+ gst_object_unref (peerpad);
+
+ if (ret) {
+ GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s",
+ (guint64) absolute_byte_offset, "succeeded");
+ } else {
+ GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s",
+ (guint64) absolute_byte_offset, "failed");
+ return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
+ }
+ } else {
+ GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " failed (no peer pad)",
+ (guint64) absolute_byte_offset);
+ }
+
+ flacenc->offset = absolute_byte_offset;
+ return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+static void
+notgst_value_array_append_buffer (GValue * array_val, GstBuffer * buf)
+{
+ GValue value = { 0, };
+
+ g_value_init (&value, GST_TYPE_BUFFER);
+ /* copy buffer to avoid problems with circular refcounts */
+ buf = gst_buffer_copy (buf);
+ /* again, for good measure */
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+ gst_value_set_buffer (&value, buf);
+ gst_buffer_unref (buf);
+ gst_value_array_append_value (array_val, &value);
+ g_value_unset (&value);
+}
+
+#define HDR_TYPE_STREAMINFO 0
+#define HDR_TYPE_VORBISCOMMENT 4
+
+static GstFlowReturn
+gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
+{
+ GstBuffer *vorbiscomment = NULL;
+ GstBuffer *streaminfo = NULL;
+ GstBuffer *marker = NULL;
+ GValue array = { 0, };
+ GstCaps *caps;
+ GList *l;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ caps = gst_caps_new_simple ("audio/x-flac",
+ "channels", G_TYPE_INT, enc->channels,
+ "rate", G_TYPE_INT, enc->sample_rate, NULL);
+
+ for (l = enc->headers; l != NULL; l = l->next) {
+ const guint8 *data;
+ guint size;
+
+ /* mark buffers so oggmux will ignore them if it already muxed the
+ * header buffers from the streamheaders field in the caps */
+ l->data = gst_buffer_make_metadata_writable (GST_BUFFER (l->data));
+ GST_BUFFER_FLAG_SET (GST_BUFFER (l->data), GST_BUFFER_FLAG_IN_CAPS);
+
+ data = GST_BUFFER_DATA (GST_BUFFER_CAST (l->data));
+ size = GST_BUFFER_SIZE (GST_BUFFER_CAST (l->data));
+
+ /* find initial 4-byte marker which we need to skip later on */
+ if (size == 4 && memcmp (data, "fLaC", 4) == 0) {
+ marker = GST_BUFFER_CAST (l->data);
+ } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_STREAMINFO) {
+ streaminfo = GST_BUFFER_CAST (l->data);
+ } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_VORBISCOMMENT) {
+ vorbiscomment = GST_BUFFER_CAST (l->data);
+ }
+ }
+
+ if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
+ GST_WARNING_OBJECT (enc, "missing header %p %p %p, muxing into container "
+ "formats may be broken", marker, streaminfo, vorbiscomment);
+ goto push_headers;
+ }
+
+ g_value_init (&array, GST_TYPE_ARRAY);
+
+ /* add marker including STREAMINFO header */
+ {
+ GstBuffer *buf;
+ guint16 num;
+
+ /* minus one for the marker that is merged with streaminfo here */
+ num = g_list_length (enc->headers) - 1;
+
+ buf = gst_buffer_new_and_alloc (13 + GST_BUFFER_SIZE (streaminfo));
+ GST_BUFFER_DATA (buf)[0] = 0x7f;
+ memcpy (GST_BUFFER_DATA (buf) + 1, "FLAC", 4);
+ GST_BUFFER_DATA (buf)[5] = 0x01; /* mapping version major */
+ GST_BUFFER_DATA (buf)[6] = 0x00; /* mapping version minor */
+ GST_BUFFER_DATA (buf)[7] = (num & 0xFF00) >> 8;
+ GST_BUFFER_DATA (buf)[8] = (num & 0x00FF) >> 0;
+ memcpy (GST_BUFFER_DATA (buf) + 9, "fLaC", 4);
+ memcpy (GST_BUFFER_DATA (buf) + 13, GST_BUFFER_DATA (streaminfo),
+ GST_BUFFER_SIZE (streaminfo));
+ notgst_value_array_append_buffer (&array, buf);
+ gst_buffer_unref (buf);
+ }
+
+ /* add VORBISCOMMENT header */
+ notgst_value_array_append_buffer (&array, vorbiscomment);
+
+ /* add other headers, if there are any */
+ for (l = enc->headers; l != NULL; l = l->next) {
+ if (GST_BUFFER_CAST (l->data) != marker &&
+ GST_BUFFER_CAST (l->data) != streaminfo &&
+ GST_BUFFER_CAST (l->data) != vorbiscomment) {
+ notgst_value_array_append_buffer (&array, GST_BUFFER_CAST (l->data));
+ }
+ }
+
+ gst_structure_set_value (gst_caps_get_structure (caps, 0),
+ "streamheader", &array);
+ g_value_unset (&array);
+
+push_headers:
+
+ /* push header buffers; update caps, so when we push the first buffer the
+ * negotiated caps will change to caps that include the streamheader field */
+ for (l = enc->headers; l != NULL; l = l->next) {
+ GstBuffer *buf;
+
+ buf = GST_BUFFER (l->data);
+ gst_buffer_set_caps (buf, caps);
+ GST_LOG_OBJECT (enc, "Pushing header buffer, size %u bytes",
+ GST_BUFFER_SIZE (buf));
+ GST_MEMDUMP_OBJECT (enc, "header buffer", GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf));
+ ret = gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buf);
+ l->data = NULL;
+ }
+ g_list_free (enc->headers);
+ enc->headers = NULL;
+
+ gst_caps_unref (caps);
+
+ return ret;
+}
+
+static FLAC__StreamEncoderWriteStatus
+gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
+ const FLAC__byte buffer[], size_t bytes,
+ unsigned samples, unsigned current_frame, void *client_data)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstFlacEnc *flacenc;
+ GstBuffer *outbuf;
+
+ flacenc = GST_FLAC_ENC (client_data);
+
+ if (flacenc->stopped)
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+
+ outbuf = gst_buffer_new_and_alloc (bytes);
+ memcpy (GST_BUFFER_DATA (outbuf), buffer, bytes);
+
+ /* we assume libflac passes us stuff neatly framed */
+ if (!flacenc->got_headers) {
+ if (samples == 0) {
+ GST_DEBUG_OBJECT (flacenc, "Got header, queueing (%u bytes)",
+ (guint) bytes);
+ flacenc->headers = g_list_append (flacenc->headers, outbuf);
+ /* note: it's important that we increase our byte offset */
+ goto out;
+ } else {
+ GST_INFO_OBJECT (flacenc, "Non-header packet, we have all headers now");
+ ret = gst_flac_enc_process_stream_headers (flacenc);
+ flacenc->got_headers = TRUE;
+ }
+ }
+
+ if (flacenc->got_headers && samples == 0) {
+ /* header fixup, push downstream directly */
+ GST_DEBUG_OBJECT (flacenc, "Fixing up headers at pos=%" G_GUINT64_FORMAT
+ ", size=%u", flacenc->offset, (guint) bytes);
+ GST_MEMDUMP_OBJECT (flacenc, "Presumed header fragment",
+ GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf));
+ gst_buffer_set_caps (outbuf,
+ GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (flacenc)));
+ ret = gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (flacenc), outbuf);
+ } else {
+ /* regular frame data, pass to base class */
+ GST_LOG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, "
+ "pos=%" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+ samples, (guint) bytes, flacenc->offset);
+ ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (flacenc),
+ outbuf, samples);
+ }
+
+ if (ret != GST_FLOW_OK)
+ GST_DEBUG_OBJECT (flacenc, "flow: %s", gst_flow_get_name (ret));
+
+ flacenc->last_flow = ret;
+
+out:
+ flacenc->offset += bytes;
+
+ if (ret != GST_FLOW_OK)
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+static FLAC__StreamEncoderTellStatus
+gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
+ FLAC__uint64 * absolute_byte_offset, void *client_data)
+{
+ GstFlacEnc *flacenc = GST_FLAC_ENC (client_data);
+
+ *absolute_byte_offset = flacenc->offset;
+
+ return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
+}
+
+static gboolean
+gst_flac_enc_sink_event (GstAudioEncoder * enc, GstEvent * event)
+{
+ GstFlacEnc *flacenc;
+ GstTagList *taglist;
+ gboolean ret = FALSE;
+
+ flacenc = GST_FLAC_ENC (enc);
+
+ GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_NEWSEGMENT:{
+ GstFormat format;
+ gint64 start, stream_time;
+
+ if (flacenc->offset == 0) {
+ gst_event_parse_new_segment (event, NULL, NULL, &format, &start, NULL,
+ &stream_time);
+ } else {
+ start = -1;
+ stream_time = -1;
+ }
+
+ if (start > 0) {
+ if (flacenc->offset > 0)
+ GST_DEBUG ("Not handling mid-stream newsegment event");
+ else
+ GST_DEBUG ("Not handling newsegment event with non-zero start");
+ } else {
+ GstEvent *e = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
+ 0, -1, 0);
+
+ ret = gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (enc), e);
+ }
+
+ if (stream_time > 0) {
+ GST_DEBUG ("Not handling non-zero stream time");
+ }
+
+ /* don't push it downstream, we'll generate our own via seek to 0 */
+ gst_event_unref (event);
+ ret = TRUE;
+ break;
+ }
+ case GST_EVENT_EOS:
+ flacenc->eos = TRUE;
+ break;
+ case GST_EVENT_TAG:
+ if (flacenc->tags) {
+ gst_event_parse_tag (event, &taglist);
+ gst_tag_list_insert (flacenc->tags, taglist,
+ gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (flacenc)));
+ } else {
+ g_assert_not_reached ();
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_flac_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
+{
+ GstFlacEnc *flacenc;
+ FLAC__int32 *data;
+ gulong insize;
+ gint samples, width;
+ gulong i;
+ FLAC__bool res;
+
+ flacenc = GST_FLAC_ENC (enc);
+
+ /* base class ensures configuration */
+ g_return_val_if_fail (flacenc->depth != 0, GST_FLOW_NOT_NEGOTIATED);
+
+ width = flacenc->width;
+
+ if (G_UNLIKELY (!buffer)) {
+ if (flacenc->eos) {
+ FLAC__stream_encoder_finish (flacenc->encoder);
+ } else {
+ /* can't handle intermittent draining/resyncing */
+ GST_ELEMENT_WARNING (flacenc, STREAM, FORMAT, (NULL),
+ ("Stream discontinuity detected. "
+ "The output may have wrong timestamps, "
+ "consider using audiorate to handle discontinuities"));
+ }
+ return flacenc->last_flow;
+ }
+
+ insize = GST_BUFFER_SIZE (buffer);
+ samples = insize / (width >> 3);
+
+ data = g_malloc (samples * sizeof (FLAC__int32));
+
+ if (width == 8) {
+ gint8 *indata = (gint8 *) GST_BUFFER_DATA (buffer);
+
+ for (i = 0; i < samples; i++)
+ data[i] = (FLAC__int32) indata[i];
+ } else if (width == 16) {
+ gint16 *indata = (gint16 *) GST_BUFFER_DATA (buffer);
+
+ for (i = 0; i < samples; i++)
+ data[i] = (FLAC__int32) indata[i];
+ } else if (width == 32) {
+ gint32 *indata = (gint32 *) GST_BUFFER_DATA (buffer);
+
+ for (i = 0; i < samples; i++)
+ data[i] = (FLAC__int32) indata[i];
+ } else {
+ g_assert_not_reached ();
+ }
+
+ res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
+ (const FLAC__int32 *) data, samples / flacenc->channels);
+
+ g_free (data);
+
+ if (!res) {
+ if (flacenc->last_flow == GST_FLOW_OK)
+ return GST_FLOW_ERROR;
+ else
+ return flacenc->last_flow;
+ }
+
+ return GST_FLOW_OK;
+}
+
+static void
+gst_flac_enc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstFlacEnc *this = GST_FLAC_ENC (object);
+
+ GST_OBJECT_LOCK (this);
+
+ switch (prop_id) {
+ case PROP_QUALITY:
+ gst_flac_enc_update_quality (this, g_value_get_enum (value));
+ break;
+ case PROP_STREAMABLE_SUBSET:
+ FLAC__stream_encoder_set_streamable_subset (this->encoder,
+ g_value_get_boolean (value));
+ break;
+ case PROP_MID_SIDE_STEREO:
+ FLAC__stream_encoder_set_do_mid_side_stereo (this->encoder,
+ g_value_get_boolean (value));
+ break;
+ case PROP_LOOSE_MID_SIDE_STEREO:
+ FLAC__stream_encoder_set_loose_mid_side_stereo (this->encoder,
+ g_value_get_boolean (value));
+ break;
+ case PROP_BLOCKSIZE:
+ FLAC__stream_encoder_set_blocksize (this->encoder,
+ g_value_get_uint (value));
+ break;
+ case PROP_MAX_LPC_ORDER:
+ FLAC__stream_encoder_set_max_lpc_order (this->encoder,
+ g_value_get_uint (value));
+ break;
+ case PROP_QLP_COEFF_PRECISION:
+ FLAC__stream_encoder_set_qlp_coeff_precision (this->encoder,
+ g_value_get_uint (value));
+ break;
+ case PROP_QLP_COEFF_PREC_SEARCH:
+ FLAC__stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
+ g_value_get_boolean (value));
+ break;
+ case PROP_ESCAPE_CODING:
+ FLAC__stream_encoder_set_do_escape_coding (this->encoder,
+ g_value_get_boolean (value));
+ break;
+ case PROP_EXHAUSTIVE_MODEL_SEARCH:
+ FLAC__stream_encoder_set_do_exhaustive_model_search (this->encoder,
+ g_value_get_boolean (value));
+ break;
+ case PROP_MIN_RESIDUAL_PARTITION_ORDER:
+ FLAC__stream_encoder_set_min_residual_partition_order (this->encoder,
+ g_value_get_uint (value));
+ break;
+ case PROP_MAX_RESIDUAL_PARTITION_ORDER:
+ FLAC__stream_encoder_set_max_residual_partition_order (this->encoder,
+ g_value_get_uint (value));
+ break;
+ case PROP_RICE_PARAMETER_SEARCH_DIST:
+ FLAC__stream_encoder_set_rice_parameter_search_dist (this->encoder,
+ g_value_get_uint (value));
+ break;
+ case PROP_PADDING:
+ this->padding = g_value_get_uint (value);
+ break;
+ case PROP_SEEKPOINTS:
+ this->seekpoints = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ GST_OBJECT_UNLOCK (this);
+}
+
+static void
+gst_flac_enc_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstFlacEnc *this = GST_FLAC_ENC (object);
+
+ GST_OBJECT_LOCK (this);
+
+ switch (prop_id) {
+ case PROP_QUALITY:
+ g_value_set_enum (value, this->quality);
+ break;
+ case PROP_STREAMABLE_SUBSET:
+ g_value_set_boolean (value,
+ FLAC__stream_encoder_get_streamable_subset (this->encoder));
+ break;
+ case PROP_MID_SIDE_STEREO:
+ g_value_set_boolean (value,
+ FLAC__stream_encoder_get_do_mid_side_stereo (this->encoder));
+ break;
+ case PROP_LOOSE_MID_SIDE_STEREO:
+ g_value_set_boolean (value,
+ FLAC__stream_encoder_get_loose_mid_side_stereo (this->encoder));
+ break;
+ case PROP_BLOCKSIZE:
+ g_value_set_uint (value,
+ FLAC__stream_encoder_get_blocksize (this->encoder));
+ break;
+ case PROP_MAX_LPC_ORDER:
+ g_value_set_uint (value,
+ FLAC__stream_encoder_get_max_lpc_order (this->encoder));
+ break;
+ case PROP_QLP_COEFF_PRECISION:
+ g_value_set_uint (value,
+ FLAC__stream_encoder_get_qlp_coeff_precision (this->encoder));
+ break;
+ case PROP_QLP_COEFF_PREC_SEARCH:
+ g_value_set_boolean (value,
+ FLAC__stream_encoder_get_do_qlp_coeff_prec_search (this->encoder));
+ break;
+ case PROP_ESCAPE_CODING:
+ g_value_set_boolean (value,
+ FLAC__stream_encoder_get_do_escape_coding (this->encoder));
+ break;
+ case PROP_EXHAUSTIVE_MODEL_SEARCH:
+ g_value_set_boolean (value,
+ FLAC__stream_encoder_get_do_exhaustive_model_search (this->encoder));
+ break;
+ case PROP_MIN_RESIDUAL_PARTITION_ORDER:
+ g_value_set_uint (value,
+ FLAC__stream_encoder_get_min_residual_partition_order
+ (this->encoder));
+ break;
+ case PROP_MAX_RESIDUAL_PARTITION_ORDER:
+ g_value_set_uint (value,
+ FLAC__stream_encoder_get_max_residual_partition_order
+ (this->encoder));
+ break;
+ case PROP_RICE_PARAMETER_SEARCH_DIST:
+ g_value_set_uint (value,
+ FLAC__stream_encoder_get_rice_parameter_search_dist (this->encoder));
+ break;
+ case PROP_PADDING:
+ g_value_set_uint (value, this->padding);
+ break;
+ case PROP_SEEKPOINTS:
+ g_value_set_int (value, this->seekpoints);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ GST_OBJECT_UNLOCK (this);
+}
diff --git a/ext/flac/gstflacenc.h b/ext/flac/gstflacenc.h
new file mode 100644
index 0000000..9084892
--- /dev/null
+++ b/ext/flac/gstflacenc.h
@@ -0,0 +1,79 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_FLAC_ENC_H__
+#define __GST_FLAC_ENC_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudioencoder.h>
+
+#include <FLAC/all.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_FLAC_ENC (gst_flac_enc_get_type())
+#define GST_FLAC_ENC(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, GST_TYPE_FLAC_ENC, GstFlacEnc)
+#define GST_FLAC_ENC_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, GST_TYPE_FLAC_ENC, GstFlacEncClass)
+#define GST_IS_FLAC_ENC(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, GST_TYPE_FLAC_ENC)
+#define GST_IS_FLAC_ENC_CLASS(klass) G_TYPE_CHECK_CLASS_TYPE(klass, GST_TYPE_FLAC_ENC)
+
+typedef struct _GstFlacEnc GstFlacEnc;
+typedef struct _GstFlacEncClass GstFlacEncClass;
+
+struct _GstFlacEnc {
+ GstAudioEncoder element;
+
+ /* < private > */
+
+ GstFlowReturn last_flow; /* save flow from last push so we can pass the
+ * correct flow return upstream in case the push
+ * fails for some reason */
+
+ guint64 offset;
+ gint channels;
+ gint width;
+ gint depth;
+ gint sample_rate;
+ gint quality;
+ gboolean stopped;
+ guint padding;
+ gint seekpoints;
+
+ FLAC__StreamEncoder *encoder;
+
+ FLAC__StreamMetadata **meta;
+
+ GstTagList * tags;
+
+ gboolean eos;
+ /* queue headers until we have them all so we can add streamheaders to caps */
+ gboolean got_headers;
+ GList *headers;
+};
+
+struct _GstFlacEncClass {
+ GstAudioEncoderClass parent_class;
+};
+
+GType gst_flac_enc_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_FLAC_ENC_H__ */
diff --git a/ext/flac/gstflactag.c b/ext/flac/gstflactag.c
new file mode 100644
index 0000000..ff06ce9
--- /dev/null
+++ b/ext/flac/gstflactag.c
@@ -0,0 +1,490 @@
+/* GStreamer
+ * Copyright (C) 2003 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2008 Jonathan Matthew <jonathan@d14n.org>
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * gstflactag.c: plug-in for reading/modifying vorbis comments in flac files
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-flactag
+ * @see_also: #flacenc, #flacdec, #GstTagSetter
+ *
+ * The flactag element can change the tag contained within a raw
+ * FLAC stream. Specifically, it modifies the comments header packet
+ * of the FLAC stream.
+ *
+ * Applications can set the tags to write using the #GstTagSetter interface.
+ * Tags contained withing the FLAC bitstream will be picked up
+ * automatically (and merged according to the merge mode set via the tag
+ * setter interface).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch -v filesrc location=foo.flac ! flactag ! filesink location=bar.flac
+ * ]| This element is not useful with gst-launch, because it does not support
+ * setting the tags on a #GstTagSetter interface. Conceptually, the element
+ * will usually be used in this order though.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/gsttagsetter.h>
+#include <gst/base/gstadapter.h>
+#include <gst/tag/tag.h>
+#include <string.h>
+
+#include "gstflactag.h"
+
+GST_DEBUG_CATEGORY_STATIC (flactag_debug);
+#define GST_CAT_DEFAULT flactag_debug
+
+/* elementfactory information */
+static GstStaticPadTemplate flac_tag_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-flac")
+ );
+
+static GstStaticPadTemplate flac_tag_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-flac")
+ );
+
+/* signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0
+ /* FILL ME */
+};
+
+static void gst_flac_tag_dispose (GObject * object);
+
+static GstFlowReturn gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer);
+
+static GstStateChangeReturn gst_flac_tag_change_state (GstElement * element,
+ GstStateChange transition);
+
+static gboolean gst_flac_tag_sink_setcaps (GstPad * pad, GstCaps * caps);
+
+static void
+gst_flac_tag_setup_interfaces (GType flac_tag_type)
+{
+ static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
+
+ g_type_add_interface_static (flac_tag_type, GST_TYPE_TAG_SETTER,
+ &tag_setter_info);
+}
+
+GST_BOILERPLATE_FULL (GstFlacTag, gst_flac_tag, GstElement, GST_TYPE_ELEMENT,
+ gst_flac_tag_setup_interfaces);
+
+static void
+gst_flac_tag_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details_simple (element_class, "FLAC tagger",
+ "Formatter/Metadata",
+ "Rewrite tags in a FLAC file", "Christophe Fergeau <teuf@gnome.org>");
+
+ gst_element_class_add_static_pad_template (element_class,
+ &flac_tag_sink_template);
+ gst_element_class_add_static_pad_template (element_class,
+ &flac_tag_src_template);
+
+ GST_DEBUG_CATEGORY_INIT (flactag_debug, "flactag", 0, "flac tag rewriter");
+}
+
+static void
+gst_flac_tag_class_init (GstFlacTagClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GObjectClass *gobject_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gobject_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->dispose = gst_flac_tag_dispose;
+ gstelement_class->change_state = gst_flac_tag_change_state;
+}
+
+static void
+gst_flac_tag_dispose (GObject * object)
+{
+ GstFlacTag *tag = GST_FLAC_TAG (object);
+
+ if (tag->adapter) {
+ g_object_unref (tag->adapter);
+ tag->adapter = NULL;
+ }
+ if (tag->vorbiscomment) {
+ gst_buffer_unref (tag->vorbiscomment);
+ tag->vorbiscomment = NULL;
+ }
+ if (tag->tags) {
+ gst_tag_list_free (tag->tags);
+ tag->tags = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+
+static void
+gst_flac_tag_init (GstFlacTag * tag, GstFlacTagClass * klass)
+{
+ /* create the sink and src pads */
+ tag->sinkpad =
+ gst_pad_new_from_static_template (&flac_tag_sink_template, "sink");
+ gst_pad_set_chain_function (tag->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_flac_tag_chain));
+ gst_pad_set_setcaps_function (tag->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_flac_tag_sink_setcaps));
+ gst_element_add_pad (GST_ELEMENT (tag), tag->sinkpad);
+
+ tag->srcpad =
+ gst_pad_new_from_static_template (&flac_tag_src_template, "src");
+ gst_element_add_pad (GST_ELEMENT (tag), tag->srcpad);
+
+ tag->adapter = gst_adapter_new ();
+}
+
+static gboolean
+gst_flac_tag_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstFlacTag *tag = GST_FLAC_TAG (GST_PAD_PARENT (pad));
+
+ return gst_pad_set_caps (tag->srcpad, caps);
+}
+
+#define FLAC_MAGIC "fLaC"
+#define FLAC_MAGIC_SIZE (sizeof (FLAC_MAGIC) - 1)
+
+static GstFlowReturn
+gst_flac_tag_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstFlacTag *tag;
+ GstFlowReturn ret;
+
+ ret = GST_FLOW_OK;
+ tag = GST_FLAC_TAG (gst_pad_get_parent (pad));
+
+ gst_adapter_push (tag->adapter, buffer);
+
+ /* Initial state, we don't even know if we are dealing with a flac file */
+ if (tag->state == GST_FLAC_TAG_STATE_INIT) {
+ GstBuffer *id_buffer;
+
+ if (gst_adapter_available (tag->adapter) < sizeof (FLAC_MAGIC))
+ goto cleanup;
+
+ id_buffer = gst_adapter_take_buffer (tag->adapter, FLAC_MAGIC_SIZE);
+ GST_DEBUG_OBJECT (tag, "looking for " FLAC_MAGIC " identifier");
+ if (memcmp (GST_BUFFER_DATA (id_buffer), FLAC_MAGIC, FLAC_MAGIC_SIZE) == 0) {
+
+ GST_DEBUG_OBJECT (tag, "pushing " FLAC_MAGIC " identifier buffer");
+ gst_buffer_set_caps (id_buffer, GST_PAD_CAPS (tag->srcpad));
+ ret = gst_pad_push (tag->srcpad, id_buffer);
+ if (ret != GST_FLOW_OK)
+ goto cleanup;
+
+ tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS;
+ } else {
+ /* FIXME: does that work well with FLAC files containing ID3v2 tags ? */
+ gst_buffer_unref (id_buffer);
+ GST_ELEMENT_ERROR (tag, STREAM, WRONG_TYPE, (NULL), (NULL));
+ ret = GST_FLOW_ERROR;
+ }
+ }
+
+
+ /* The fLaC magic string has been skipped, try to detect the beginning
+ * of a metadata block
+ */
+ if (tag->state == GST_FLAC_TAG_STATE_METADATA_BLOCKS) {
+ guint size;
+ guint type;
+ gboolean is_last;
+ const guint8 *block_header;
+
+ g_assert (tag->metadata_block_size == 0);
+ g_assert (tag->metadata_last_block == FALSE);
+
+ /* The header of a flac metadata block is 4 bytes long:
+ * 1st bit: indicates whether this is the last metadata info block
+ * 7 next bits: 4 if vorbis comment block
+ * 24 next bits: size of the metadata to follow (big endian)
+ */
+ if (gst_adapter_available (tag->adapter) < 4)
+ goto cleanup;
+
+ block_header = gst_adapter_peek (tag->adapter, 4);
+
+ is_last = ((block_header[0] & 0x80) == 0x80);
+ type = block_header[0] & 0x7F;
+ size = (block_header[1] << 16)
+ | (block_header[2] << 8)
+ | block_header[3];
+
+ /* The 4 bytes long header isn't included in the metadata size */
+ tag->metadata_block_size = size + 4;
+ tag->metadata_last_block = is_last;
+
+ GST_DEBUG_OBJECT (tag,
+ "got metadata block: %d bytes, type %d, is vorbiscomment: %d, is last: %d",
+ size, type, (type == 0x04), is_last);
+
+ /* Metadata blocks of type 4 are vorbis comment blocks */
+ if (type == 0x04) {
+ tag->state = GST_FLAC_TAG_STATE_VC_METADATA_BLOCK;
+ } else {
+ tag->state = GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK;
+ }
+ }
+
+
+ /* Reads a metadata block */
+ if ((tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) ||
+ (tag->state == GST_FLAC_TAG_STATE_VC_METADATA_BLOCK)) {
+ GstBuffer *metadata_buffer;
+
+ if (gst_adapter_available (tag->adapter) < tag->metadata_block_size)
+ goto cleanup;
+
+ metadata_buffer = gst_adapter_take_buffer (tag->adapter,
+ tag->metadata_block_size);
+ /* clear the is-last flag, as the last metadata block will
+ * be the vorbis comment block which we will build ourselves.
+ */
+ GST_BUFFER_DATA (metadata_buffer)[0] &= (~0x80);
+
+ if (tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) {
+ GST_DEBUG_OBJECT (tag, "pushing metadata block buffer");
+ gst_buffer_set_caps (metadata_buffer, GST_PAD_CAPS (tag->srcpad));
+ ret = gst_pad_push (tag->srcpad, metadata_buffer);
+ if (ret != GST_FLOW_OK)
+ goto cleanup;
+ } else {
+ tag->vorbiscomment = metadata_buffer;
+ }
+ tag->metadata_block_size = 0;
+ tag->state = GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK;
+ }
+
+ /* This state is mainly used to be able to stop as soon as we read
+ * a vorbiscomment block from the flac file if we are in an only output
+ * tags mode
+ */
+ if (tag->state == GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK) {
+ /* Check if in the previous iteration we read a vorbis comment metadata
+ * block, and stop now if the user only wants to read tags
+ */
+ if (tag->vorbiscomment != NULL) {
+ /* We found some tags, try to parse them and notify the other elements
+ * that we encountered some tags
+ */
+ GST_DEBUG_OBJECT (tag, "emitting vorbiscomment tags");
+ tag->tags = gst_tag_list_from_vorbiscomment_buffer (tag->vorbiscomment,
+ GST_BUFFER_DATA (tag->vorbiscomment), 4, NULL);
+ if (tag->tags != NULL) {
+ gst_element_found_tags (GST_ELEMENT (tag),
+ gst_tag_list_copy (tag->tags));
+ }
+
+ gst_buffer_unref (tag->vorbiscomment);
+ tag->vorbiscomment = NULL;
+ }
+
+ /* Skip to next state */
+ if (tag->metadata_last_block == FALSE) {
+ tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS;
+ } else {
+ tag->state = GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT;
+ }
+ }
+
+
+ /* Creates a vorbis comment block from the metadata which was set
+ * on the gstreamer element, and add it to the flac stream
+ */
+ if (tag->state == GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT) {
+ GstBuffer *buffer;
+ gint size;
+ const GstTagList *user_tags;
+ GstTagList *merged_tags;
+
+ /* merge the tag lists */
+ user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (tag));
+ if (user_tags != NULL) {
+ merged_tags = gst_tag_list_merge (user_tags, tag->tags,
+ gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (tag)));
+ } else {
+ merged_tags = gst_tag_list_copy (tag->tags);
+ }
+
+ if (merged_tags == NULL) {
+ /* If we get a NULL list of tags, we must generate a padding block
+ * which is marked as the last metadata block, otherwise we'll
+ * end up with a corrupted flac file.
+ */
+ GST_WARNING_OBJECT (tag, "No tags found");
+ buffer = gst_buffer_new_and_alloc (12);
+ if (buffer == NULL) {
+ GST_ELEMENT_ERROR (tag, CORE, TOO_LAZY, (NULL),
+ ("Error creating 12-byte buffer for padding block"));
+ ret = GST_FLOW_ERROR;
+ goto cleanup;
+ }
+ memset (GST_BUFFER_DATA (buffer), 0, GST_BUFFER_SIZE (buffer));
+ GST_BUFFER_DATA (buffer)[0] = 0x81; /* 0x80 = Last metadata block,
+ * 0x01 = padding block
+ */
+ } else {
+ guchar header[4];
+
+ memset (header, 0, sizeof (header));
+ header[0] = 0x84; /* 0x80 = Last metadata block,
+ * 0x04 = vorbiscomment block
+ */
+ buffer = gst_tag_list_to_vorbiscomment_buffer (merged_tags, header,
+ sizeof (header), NULL);
+ GST_DEBUG_OBJECT (tag, "Writing tags %" GST_PTR_FORMAT, merged_tags);
+ gst_tag_list_free (merged_tags);
+ if (buffer == NULL) {
+ GST_ELEMENT_ERROR (tag, CORE, TAG, (NULL),
+ ("Error converting tag list to vorbiscomment buffer"));
+ ret = GST_FLOW_ERROR;
+ goto cleanup;
+ }
+ size = GST_BUFFER_SIZE (buffer) - 4;
+ if ((size > 0xFFFFFF) || (size < 0)) {
+ /* FLAC vorbis comment blocks are limited to 2^24 bytes,
+ * while the vorbis specs allow more than that. Shouldn't
+ * be a real world problem though
+ */
+ GST_ELEMENT_ERROR (tag, CORE, TAG, (NULL),
+ ("Vorbis comment of size %d too long", size));
+ ret = GST_FLOW_ERROR;
+ goto cleanup;
+ }
+
+ /* Get rid of the framing bit at the end of the vorbiscomment buffer
+ * if it exists since libFLAC seems to lose sync because of this
+ * bit in gstflacdec
+ */
+ if (GST_BUFFER_DATA (buffer)[GST_BUFFER_SIZE (buffer) - 1] == 1) {
+ GstBuffer *sub;
+
+ sub = gst_buffer_create_sub (buffer, 0, GST_BUFFER_SIZE (buffer) - 1);
+ gst_buffer_unref (buffer);
+ buffer = sub;
+ }
+ }
+
+ /* The 4 byte metadata block header isn't accounted for in the total
+ * size of the metadata block
+ */
+ size = GST_BUFFER_SIZE (buffer) - 4;
+
+ GST_BUFFER_DATA (buffer)[1] = ((size & 0xFF0000) >> 16);
+ GST_BUFFER_DATA (buffer)[2] = ((size & 0x00FF00) >> 8);
+ GST_BUFFER_DATA (buffer)[3] = (size & 0x0000FF);
+ GST_DEBUG_OBJECT (tag, "pushing %d byte vorbiscomment buffer",
+ GST_BUFFER_SIZE (buffer));
+ gst_buffer_set_caps (buffer, GST_PAD_CAPS (tag->srcpad));
+ ret = gst_pad_push (tag->srcpad, buffer);
+ if (ret != GST_FLOW_OK) {
+ goto cleanup;
+ }
+ tag->state = GST_FLAC_TAG_STATE_AUDIO_DATA;
+ }
+
+ /* The metadata blocks have been read, now we are reading audio data */
+ if (tag->state == GST_FLAC_TAG_STATE_AUDIO_DATA) {
+ GstBuffer *buffer;
+ guint avail;
+
+ avail = gst_adapter_available (tag->adapter);
+ if (avail > 0) {
+ buffer = gst_adapter_take_buffer (tag->adapter, avail);
+ gst_buffer_set_caps (buffer, GST_PAD_CAPS (tag->srcpad));
+ ret = gst_pad_push (tag->srcpad, buffer);
+ }
+ }
+
+cleanup:
+ gst_object_unref (tag);
+
+ return ret;
+}
+
+
+static GstStateChangeReturn
+gst_flac_tag_change_state (GstElement * element, GstStateChange transition)
+{
+ GstFlacTag *tag;
+
+ tag = GST_FLAC_TAG (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ /* do something to get out of the chain function faster */
+ break;
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_adapter_clear (tag->adapter);
+ if (tag->vorbiscomment) {
+ gst_buffer_unref (tag->vorbiscomment);
+ tag->vorbiscomment = NULL;
+ }
+ if (tag->tags) {
+ gst_tag_list_free (tag->tags);
+ tag->tags = NULL;
+ }
+ tag->metadata_block_size = 0;
+ tag->metadata_last_block = FALSE;
+ tag->state = GST_FLAC_TAG_STATE_INIT;
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ }
+
+ return parent_class->change_state (element, transition);
+}
diff --git a/ext/flac/gstflactag.h b/ext/flac/gstflactag.h
new file mode 100644
index 0000000..a6f90f5
--- /dev/null
+++ b/ext/flac/gstflactag.h
@@ -0,0 +1,78 @@
+/* GStreamer
+ * Copyright (C) 2003 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2008 Jonathan Matthew <jonathan@d14n.org>
+ * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * gstflactag.c: plug-in for reading/modifying vorbis comments in flac files
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GST_FLAC_TAG_H
+#define GST_FLAC_TAG_H
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+#define GST_TYPE_FLAC_TAG (gst_flac_tag_get_type())
+#define GST_FLAC_TAG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLAC_TAG, GstFlacTag))
+#define GST_FLAC_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLAC_TAG, GstFlacTag))
+#define GST_IS_FLAC_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLAC_TAG))
+#define GST_IS_FLAC_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLAC_TAG))
+
+typedef struct _GstFlacTag GstFlacTag;
+typedef struct _GstFlacTagClass GstFlacTagClass;
+
+typedef enum
+{
+ GST_FLAC_TAG_STATE_INIT,
+ GST_FLAC_TAG_STATE_METADATA_BLOCKS,
+ GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK,
+ GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK,
+ GST_FLAC_TAG_STATE_VC_METADATA_BLOCK,
+ GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT,
+ GST_FLAC_TAG_STATE_AUDIO_DATA
+}
+GstFlacTagState;
+
+struct _GstFlacTag
+{
+ GstElement element;
+
+ /* < private > */
+
+ /* pads */
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ GstFlacTagState state;
+
+ GstAdapter *adapter;
+ GstBuffer *vorbiscomment;
+ GstTagList *tags;
+
+ guint metadata_block_size;
+ gboolean metadata_last_block;
+};
+
+struct _GstFlacTagClass
+{
+ GstElementClass parent_class;
+};
+
+GType gst_flac_tag_get_type (void);
+
+#endif /* GST_FLAC_TAG_H */
diff --git a/ext/gconf/Makefile.am b/ext/gconf/Makefile.am
new file mode 100644
index 0000000..0f1cffb
--- /dev/null
+++ b/ext/gconf/Makefile.am
@@ -0,0 +1,27 @@
+plugin_LTLIBRARIES = libgstgconfelements.la
+
+libgstgconfelements_la_SOURCES = \
+ gstgconfaudiosink.c \
+ gstgconfaudiosrc.c \
+ gstgconfelements.c \
+ gstgconfvideosink.c \
+ gstgconfvideosrc.c \
+ gstswitchsink.c \
+ gstswitchsrc.c \
+ gstgconf.c
+
+DIR_CFLAGS = -DGST_GCONF_DIR=\"/system/gstreamer/@GST_MAJORMINOR@\"
+libgstgconfelements_la_CFLAGS = $(GST_CFLAGS) $(GCONF_CFLAGS) $(DIR_CFLAGS)
+libgstgconfelements_la_LIBADD = $(GST_LIBS) $(GCONF_LIBS)
+libgstgconfelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstgconfelements_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = \
+ gstgconfaudiosink.h \
+ gstgconfaudiosrc.h \
+ gstgconfelements.h \
+ gstgconfvideosink.h \
+ gstgconfvideosrc.h \
+ gstswitchsink.h \
+ gstswitchsrc.h \
+ gstgconf.h
diff --git a/ext/gconf/Makefile.in b/ext/gconf/Makefile.in
new file mode 100644
index 0000000..ebcd7e1
--- /dev/null
+++ b/ext/gconf/Makefile.in
@@ -0,0 +1,888 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/gconf
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstgconfelements_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgstgconfelements_la_OBJECTS = \
+ libgstgconfelements_la-gstgconfaudiosink.lo \
+ libgstgconfelements_la-gstgconfaudiosrc.lo \
+ libgstgconfelements_la-gstgconfelements.lo \
+ libgstgconfelements_la-gstgconfvideosink.lo \
+ libgstgconfelements_la-gstgconfvideosrc.lo \
+ libgstgconfelements_la-gstswitchsink.lo \
+ libgstgconfelements_la-gstswitchsrc.lo \
+ libgstgconfelements_la-gstgconf.lo
+libgstgconfelements_la_OBJECTS = $(am_libgstgconfelements_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstgconfelements_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) \
+ $(libgstgconfelements_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstgconfelements_la_SOURCES)
+DIST_SOURCES = $(libgstgconfelements_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstgconfelements.la
+libgstgconfelements_la_SOURCES = \
+ gstgconfaudiosink.c \
+ gstgconfaudiosrc.c \
+ gstgconfelements.c \
+ gstgconfvideosink.c \
+ gstgconfvideosrc.c \
+ gstswitchsink.c \
+ gstswitchsrc.c \
+ gstgconf.c
+
+DIR_CFLAGS = -DGST_GCONF_DIR=\"/system/gstreamer/@GST_MAJORMINOR@\"
+libgstgconfelements_la_CFLAGS = $(GST_CFLAGS) $(GCONF_CFLAGS) $(DIR_CFLAGS)
+libgstgconfelements_la_LIBADD = $(GST_LIBS) $(GCONF_LIBS)
+libgstgconfelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstgconfelements_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = \
+ gstgconfaudiosink.h \
+ gstgconfaudiosrc.h \
+ gstgconfelements.h \
+ gstgconfvideosink.h \
+ gstgconfvideosrc.h \
+ gstswitchsink.h \
+ gstswitchsrc.h \
+ gstgconf.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/gconf/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/gconf/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstgconfelements.la: $(libgstgconfelements_la_OBJECTS) $(libgstgconfelements_la_DEPENDENCIES) $(EXTRA_libgstgconfelements_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstgconfelements_la_LINK) -rpath $(plugindir) $(libgstgconfelements_la_OBJECTS) $(libgstgconfelements_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstgconfelements_la-gstgconf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstgconfelements_la-gstgconfaudiosink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstgconfelements_la-gstgconfaudiosrc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstgconfelements_la-gstgconfelements.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstgconfelements_la-gstgconfvideosink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstgconfelements_la-gstgconfvideosrc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstgconfelements_la-gstswitchsink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstgconfelements_la-gstswitchsrc.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstgconfelements_la-gstgconfaudiosink.lo: gstgconfaudiosink.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -MT libgstgconfelements_la-gstgconfaudiosink.lo -MD -MP -MF $(DEPDIR)/libgstgconfelements_la-gstgconfaudiosink.Tpo -c -o libgstgconfelements_la-gstgconfaudiosink.lo `test -f 'gstgconfaudiosink.c' || echo '$(srcdir)/'`gstgconfaudiosink.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstgconfelements_la-gstgconfaudiosink.Tpo $(DEPDIR)/libgstgconfelements_la-gstgconfaudiosink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstgconfaudiosink.c' object='libgstgconfelements_la-gstgconfaudiosink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -c -o libgstgconfelements_la-gstgconfaudiosink.lo `test -f 'gstgconfaudiosink.c' || echo '$(srcdir)/'`gstgconfaudiosink.c
+
+libgstgconfelements_la-gstgconfaudiosrc.lo: gstgconfaudiosrc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -MT libgstgconfelements_la-gstgconfaudiosrc.lo -MD -MP -MF $(DEPDIR)/libgstgconfelements_la-gstgconfaudiosrc.Tpo -c -o libgstgconfelements_la-gstgconfaudiosrc.lo `test -f 'gstgconfaudiosrc.c' || echo '$(srcdir)/'`gstgconfaudiosrc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstgconfelements_la-gstgconfaudiosrc.Tpo $(DEPDIR)/libgstgconfelements_la-gstgconfaudiosrc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstgconfaudiosrc.c' object='libgstgconfelements_la-gstgconfaudiosrc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -c -o libgstgconfelements_la-gstgconfaudiosrc.lo `test -f 'gstgconfaudiosrc.c' || echo '$(srcdir)/'`gstgconfaudiosrc.c
+
+libgstgconfelements_la-gstgconfelements.lo: gstgconfelements.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -MT libgstgconfelements_la-gstgconfelements.lo -MD -MP -MF $(DEPDIR)/libgstgconfelements_la-gstgconfelements.Tpo -c -o libgstgconfelements_la-gstgconfelements.lo `test -f 'gstgconfelements.c' || echo '$(srcdir)/'`gstgconfelements.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstgconfelements_la-gstgconfelements.Tpo $(DEPDIR)/libgstgconfelements_la-gstgconfelements.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstgconfelements.c' object='libgstgconfelements_la-gstgconfelements.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -c -o libgstgconfelements_la-gstgconfelements.lo `test -f 'gstgconfelements.c' || echo '$(srcdir)/'`gstgconfelements.c
+
+libgstgconfelements_la-gstgconfvideosink.lo: gstgconfvideosink.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -MT libgstgconfelements_la-gstgconfvideosink.lo -MD -MP -MF $(DEPDIR)/libgstgconfelements_la-gstgconfvideosink.Tpo -c -o libgstgconfelements_la-gstgconfvideosink.lo `test -f 'gstgconfvideosink.c' || echo '$(srcdir)/'`gstgconfvideosink.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstgconfelements_la-gstgconfvideosink.Tpo $(DEPDIR)/libgstgconfelements_la-gstgconfvideosink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstgconfvideosink.c' object='libgstgconfelements_la-gstgconfvideosink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -c -o libgstgconfelements_la-gstgconfvideosink.lo `test -f 'gstgconfvideosink.c' || echo '$(srcdir)/'`gstgconfvideosink.c
+
+libgstgconfelements_la-gstgconfvideosrc.lo: gstgconfvideosrc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -MT libgstgconfelements_la-gstgconfvideosrc.lo -MD -MP -MF $(DEPDIR)/libgstgconfelements_la-gstgconfvideosrc.Tpo -c -o libgstgconfelements_la-gstgconfvideosrc.lo `test -f 'gstgconfvideosrc.c' || echo '$(srcdir)/'`gstgconfvideosrc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstgconfelements_la-gstgconfvideosrc.Tpo $(DEPDIR)/libgstgconfelements_la-gstgconfvideosrc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstgconfvideosrc.c' object='libgstgconfelements_la-gstgconfvideosrc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -c -o libgstgconfelements_la-gstgconfvideosrc.lo `test -f 'gstgconfvideosrc.c' || echo '$(srcdir)/'`gstgconfvideosrc.c
+
+libgstgconfelements_la-gstswitchsink.lo: gstswitchsink.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -MT libgstgconfelements_la-gstswitchsink.lo -MD -MP -MF $(DEPDIR)/libgstgconfelements_la-gstswitchsink.Tpo -c -o libgstgconfelements_la-gstswitchsink.lo `test -f 'gstswitchsink.c' || echo '$(srcdir)/'`gstswitchsink.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstgconfelements_la-gstswitchsink.Tpo $(DEPDIR)/libgstgconfelements_la-gstswitchsink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstswitchsink.c' object='libgstgconfelements_la-gstswitchsink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -c -o libgstgconfelements_la-gstswitchsink.lo `test -f 'gstswitchsink.c' || echo '$(srcdir)/'`gstswitchsink.c
+
+libgstgconfelements_la-gstswitchsrc.lo: gstswitchsrc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -MT libgstgconfelements_la-gstswitchsrc.lo -MD -MP -MF $(DEPDIR)/libgstgconfelements_la-gstswitchsrc.Tpo -c -o libgstgconfelements_la-gstswitchsrc.lo `test -f 'gstswitchsrc.c' || echo '$(srcdir)/'`gstswitchsrc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstgconfelements_la-gstswitchsrc.Tpo $(DEPDIR)/libgstgconfelements_la-gstswitchsrc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstswitchsrc.c' object='libgstgconfelements_la-gstswitchsrc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -c -o libgstgconfelements_la-gstswitchsrc.lo `test -f 'gstswitchsrc.c' || echo '$(srcdir)/'`gstswitchsrc.c
+
+libgstgconfelements_la-gstgconf.lo: gstgconf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -MT libgstgconfelements_la-gstgconf.lo -MD -MP -MF $(DEPDIR)/libgstgconfelements_la-gstgconf.Tpo -c -o libgstgconfelements_la-gstgconf.lo `test -f 'gstgconf.c' || echo '$(srcdir)/'`gstgconf.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstgconfelements_la-gstgconf.Tpo $(DEPDIR)/libgstgconfelements_la-gstgconf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstgconf.c' object='libgstgconfelements_la-gstgconf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgconfelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgconfelements_la_CFLAGS) $(CFLAGS) -c -o libgstgconfelements_la-gstgconf.lo `test -f 'gstgconf.c' || echo '$(srcdir)/'`gstgconf.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/gconf/gstgconf.c b/ext/gconf/gstgconf.c
new file mode 100644
index 0000000..eee80c9
--- /dev/null
+++ b/ext/gconf/gstgconf.c
@@ -0,0 +1,304 @@
+/* GStreamer
+ * nf_get_default_audio_sink
+ * Copyright (C) <2002> Thomas Vander Stichele <thomas@apestaart.org>
+ * Copyright (C) <2006> Jürg Billeter <j@bitron.ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * this library handles interaction with GConf
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "gstgconf.h"
+#include "gstgconfelements.h" /* for debug category */
+
+#ifndef GST_GCONF_DIR
+#error "GST_GCONF_DIR is not defined !"
+#endif
+
+static GConfClient *_gst_gconf_client = NULL; /* GConf connection */
+
+
+/* internal functions */
+
+static GConfClient *
+gst_gconf_get_client (void)
+{
+ if (!_gst_gconf_client)
+ _gst_gconf_client = gconf_client_get_default ();
+
+ return _gst_gconf_client;
+}
+
+/* external functions */
+
+/**
+ * gst_gconf_get_string:
+ * @key: a #gchar corresponding to the key you want to get.
+ *
+ * Get GConf key @key's string value.
+ *
+ * Returns: a newly allocated #gchar string containing @key's value,
+ * or NULL in the case of an error..
+ */
+gchar *
+gst_gconf_get_string (const gchar * key)
+{
+ GError *error = NULL;
+ gchar *value = NULL;
+ gchar *full_key;
+
+ if (!g_str_has_prefix (key, GST_GCONF_DIR))
+ full_key = g_strdup_printf ("%s/%s", GST_GCONF_DIR, key);
+ else
+ full_key = g_strdup (key);
+
+ value = gconf_client_get_string (gst_gconf_get_client (), full_key, &error);
+ g_free (full_key);
+
+ if (error) {
+ g_warning ("gst_gconf_get_string: error: %s\n", error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ return value;
+}
+
+const gchar *
+gst_gconf_get_key_for_sink_profile (GstGConfProfile profile)
+{
+ switch (profile) {
+ case GCONF_PROFILE_SOUNDS:
+ return GST_GCONF_DIR "/" GST_GCONF_AUDIOSINK_KEY;
+ case GCONF_PROFILE_MUSIC:
+ return GST_GCONF_DIR "/" GST_GCONF_MUSIC_AUDIOSINK_KEY;
+ case GCONF_PROFILE_CHAT:
+ return GST_GCONF_DIR "/" GST_GCONF_CHAT_AUDIOSINK_KEY;
+ default:
+ break;
+ }
+
+ g_return_val_if_reached (GST_GCONF_DIR "/" GST_GCONF_AUDIOSINK_KEY);
+}
+
+/**
+ * gst_gconf_set_string:
+ * @key: a #gchar corresponding to the key you want to set.
+ * @value: a #gchar containing key value.
+ *
+ * Set GConf key @key to string value @value.
+ */
+void
+gst_gconf_set_string (const gchar * key, const gchar * value)
+{
+ GError *error = NULL;
+ gchar *full_key;
+
+ if (!g_str_has_prefix (key, GST_GCONF_DIR))
+ full_key = g_strdup_printf ("%s/%s", GST_GCONF_DIR, key);
+ else
+ full_key = g_strdup (key);
+
+ gconf_client_set_string (gst_gconf_get_client (), full_key, value, &error);
+ if (error) {
+ GST_ERROR ("gst_gconf_set_string: error: %s\n", error->message);
+ g_error_free (error);
+ }
+ g_free (full_key);
+}
+
+/**
+ * gst_gconf_render_bin_from_key:
+ * @key: a #gchar string corresponding to a GConf key.
+ *
+ * Render bin from GConf key @key.
+ *
+ * Returns: a #GstElement containing the rendered bin.
+ */
+GstElement *
+gst_gconf_render_bin_from_key (const gchar * key)
+{
+ GstElement *bin = NULL;
+ gchar *value;
+
+ value = gst_gconf_get_string (key);
+
+ GST_LOG ("%s = %s", GST_STR_NULL (key), GST_STR_NULL (value));
+
+ if (value) {
+ GError *err = NULL;
+
+ bin = gst_parse_bin_from_description (value, TRUE, &err);
+ if (err) {
+ GST_ERROR ("gconf: error creating bin '%s': %s", value, err->message);
+ g_error_free (err);
+ }
+
+ g_free (value);
+ }
+ return bin;
+}
+
+/**
+ * gst_gconf_render_bin_with_default:
+ * @bin: a #gchar string describing the pipeline to construct.
+ * @default_sink: an element to use as default if the given pipeline fails to construct.
+ *
+ * Render bin from description @bin using @default_sink element as a fallback.
+ *
+ * Returns: a #GstElement containing the rendered bin.
+ */
+GstElement *
+gst_gconf_render_bin_with_default (const gchar * bin,
+ const gchar * default_sink)
+{
+ GstElement *ret = NULL;
+ GError *err = NULL;
+
+ if (bin != NULL)
+ ret = gst_parse_bin_from_description (bin, TRUE, &err);
+
+ if (ret == NULL || err != NULL) {
+ if (err) {
+ GST_DEBUG ("Could not create audio sink from GConf settings: %s",
+ err->message);
+ g_error_free (err);
+ } else {
+ GST_DEBUG ("Could not create audio sink from GConf settings");
+ }
+
+ ret = gst_element_factory_make (default_sink, NULL);
+
+ if (!ret)
+ g_warning
+ ("Could not build GConf audio sink and the replacement %s doesn't work",
+ DEFAULT_AUDIOSINK);
+ }
+
+ return ret;
+}
+
+/**
+ * gst_gconf_get_default_video_sink:
+ *
+ * Render video output bin from GStreamer GConf key : "default/videosink".
+ * If key is invalid, the default video sink for the platform is used
+ * (typically xvimagesink or ximagesink).
+ *
+ * Returns: a #GstElement containing the video output bin, or NULL if
+ * everything failed.
+ */
+GstElement *
+gst_gconf_get_default_video_sink (void)
+{
+ GstElement *ret = gst_gconf_render_bin_from_key (GST_GCONF_VIDEOSINK_KEY);
+
+ if (!ret) {
+ ret = gst_element_factory_make (DEFAULT_VIDEOSINK, NULL);
+
+ if (!ret)
+ g_warning ("No GConf default video sink key and %s doesn't work",
+ DEFAULT_VIDEOSINK);
+ }
+
+ return ret;
+}
+
+/**
+ * gst_gconf_get_default_audio_src:
+ *
+ * Render audio acquisition bin from GStreamer GConf key : "default/audiosrc".
+ * If key is invalid, the default audio source for the plaform is used.
+ * (typically osssrc or sunaudiosrc).
+ *
+ * Returns: a #GstElement containing the audio source bin, or NULL if
+ * everything failed.
+ */
+GstElement *
+gst_gconf_get_default_audio_src (void)
+{
+ GstElement *ret = gst_gconf_render_bin_from_key (GST_GCONF_AUDIOSRC_KEY);
+
+ if (!ret) {
+ ret = gst_element_factory_make (DEFAULT_AUDIOSRC, NULL);
+
+ if (!ret)
+ g_warning ("No GConf default audio src key and %s doesn't work",
+ DEFAULT_AUDIOSRC);
+ }
+
+ return ret;
+}
+
+/**
+ * gst_gconf_get_default_video_src:
+ *
+ * Render video acquisition bin from GStreamer GConf key :
+ * "default/videosrc". If key is invalid, the default video source
+ * for the platform is used (typically videotestsrc).
+ *
+ * Returns: a #GstElement containing the video source bin, or NULL if
+ * everything failed.
+ */
+GstElement *
+gst_gconf_get_default_video_src (void)
+{
+ GstElement *ret = gst_gconf_render_bin_from_key (GST_GCONF_VIDEOSRC_KEY);
+
+ if (!ret) {
+ ret = gst_element_factory_make (DEFAULT_VIDEOSRC, NULL);
+
+ if (!ret)
+ g_warning ("No GConf default video src key and %s doesn't work",
+ DEFAULT_VIDEOSRC);
+ }
+
+ return ret;
+}
+
+/**
+ * gst_gconf_get_default_visualization_element:
+ *
+ * Render visualization bin from GStreamer GConf key : "default/visualization".
+ * If key is invalid, the default visualization element is used.
+ *
+ * Returns: a #GstElement containing the visualization bin, or NULL if
+ * everything failed.
+ */
+GstElement *
+gst_gconf_get_default_visualization_element (void)
+{
+ GstElement *ret = gst_gconf_render_bin_from_key ("default/visualization");
+
+ if (!ret) {
+ ret = gst_element_factory_make (DEFAULT_VISUALIZER, NULL);
+
+ if (!ret)
+ g_warning
+ ("No GConf default visualization plugin key and %s doesn't work",
+ DEFAULT_VISUALIZER);
+ }
+
+ return ret;
+}
diff --git a/ext/gconf/gstgconf.h b/ext/gconf/gstgconf.h
new file mode 100644
index 0000000..b1153e9
--- /dev/null
+++ b/ext/gconf/gstgconf.h
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) <2002> Thomas Vander Stichele <thomas@apestaart.org>
+ * Copyright (C) <2006> Jürg Billeter <j@bitron.ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GST_GCONF_H
+#define GST_GCONF_H
+
+/*
+ * this library handles interaction with GConf
+ */
+
+#include <gst/gst.h>
+#include <gconf/gconf-client.h>
+
+G_BEGIN_DECLS
+
+#define GST_GCONF_AUDIOSRC_KEY "default/audiosrc"
+#define GST_GCONF_AUDIOSINK_KEY "default/audiosink"
+#define GST_GCONF_MUSIC_AUDIOSINK_KEY "default/musicaudiosink"
+#define GST_GCONF_CHAT_AUDIOSINK_KEY "default/chataudiosink"
+#define GST_GCONF_VIDEOSRC_KEY "default/videosrc"
+#define GST_GCONF_VIDEOSINK_KEY "default/videosink"
+
+typedef enum
+{
+ GCONF_PROFILE_SOUNDS,
+ GCONF_PROFILE_MUSIC,
+ GCONF_PROFILE_CHAT,
+ GCONF_PROFILE_NONE /* Internal value only */
+} GstGConfProfile;
+
+gchar * gst_gconf_get_string (const gchar *key);
+void gst_gconf_set_string (const gchar *key,
+ const gchar *value);
+
+const gchar * gst_gconf_get_key_for_sink_profile (GstGConfProfile profile);
+
+GstElement * gst_gconf_render_bin_from_key (const gchar *key);
+GstElement * gst_gconf_render_bin_with_default (const gchar *bin,
+ const gchar *default_sink);
+
+GstElement * gst_gconf_get_default_video_sink (void);
+GstElement * gst_gconf_get_default_audio_sink (int profile);
+GstElement * gst_gconf_get_default_video_src (void);
+GstElement * gst_gconf_get_default_audio_src (void);
+GstElement * gst_gconf_get_default_visualization_element (void);
+
+G_END_DECLS
+
+#endif /* GST_GCONF_H */
diff --git a/ext/gconf/gstgconfaudiosink.c b/ext/gconf/gstgconfaudiosink.c
new file mode 100644
index 0000000..d60f2be
--- /dev/null
+++ b/ext/gconf/gstgconfaudiosink.c
@@ -0,0 +1,310 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2006 Jürg Billeter <j@bitron.ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:element-gconfaudiosink
+ *
+ * This element outputs sound to the audiosink that has been configured in
+ * GConf by the user.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch filesrc location=foo.ogg ! decodebin ! audioconvert ! audioresample ! gconfaudiosink
+ * ]| Play on configured audiosink
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstgconfelements.h"
+#include "gstgconfaudiosink.h"
+
+static void gst_gconf_audio_sink_dispose (GObject * object);
+static void gst_gconf_audio_sink_finalize (GstGConfAudioSink * sink);
+static void cb_change_child (GConfClient * client,
+ guint connection_id, GConfEntry * entry, gpointer data);
+static GstStateChangeReturn
+gst_gconf_audio_sink_change_state (GstElement * element,
+ GstStateChange transition);
+static void gst_gconf_switch_profile (GstGConfAudioSink * sink,
+ GstGConfProfile profile);
+
+enum
+{
+ PROP_0,
+ PROP_PROFILE
+};
+
+GST_BOILERPLATE (GstGConfAudioSink, gst_gconf_audio_sink, GstSwitchSink,
+ GST_TYPE_SWITCH_SINK);
+
+static void gst_gconf_audio_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_gconf_audio_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void
+gst_gconf_audio_sink_base_init (gpointer klass)
+{
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_set_details_simple (eklass, "GConf audio sink",
+ "Sink/Audio",
+ "Audio sink embedding the GConf-settings for audio output",
+ "Jan Schmidt <thaytan@mad.scientist.com>");
+}
+
+#define GST_TYPE_GCONF_PROFILE (gst_gconf_profile_get_type())
+static GType
+gst_gconf_profile_get_type (void)
+{
+ static GType gconf_profile_type = 0;
+ static const GEnumValue gconf_profiles[] = {
+ {GCONF_PROFILE_SOUNDS, "Sound Events", "sounds"},
+ {GCONF_PROFILE_MUSIC, "Music and Movies", "music"},
+ {GCONF_PROFILE_CHAT, "Audio/Video Conferencing", "chat"},
+ {0, NULL, NULL}
+ };
+
+ if (!gconf_profile_type) {
+ gconf_profile_type =
+ g_enum_register_static ("GstGConfProfile", gconf_profiles);
+ }
+ return gconf_profile_type;
+}
+
+static void
+gst_gconf_audio_sink_class_init (GstGConfAudioSinkClass * klass)
+{
+ GObjectClass *oklass = G_OBJECT_CLASS (klass);
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ oklass->set_property = gst_gconf_audio_sink_set_property;
+ oklass->get_property = gst_gconf_audio_sink_get_property;
+ oklass->dispose = gst_gconf_audio_sink_dispose;
+ oklass->finalize = (GObjectFinalizeFunc) gst_gconf_audio_sink_finalize;
+ eklass->change_state = gst_gconf_audio_sink_change_state;
+
+ g_object_class_install_property (oklass, PROP_PROFILE,
+ g_param_spec_enum ("profile", "Profile", "Profile",
+ GST_TYPE_GCONF_PROFILE, GCONF_PROFILE_SOUNDS,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_gconf_audio_sink_reset (GstGConfAudioSink * sink)
+{
+ gst_switch_sink_set_child (GST_SWITCH_SINK (sink), NULL);
+
+ g_free (sink->gconf_str);
+ sink->gconf_str = NULL;
+}
+
+static void
+gst_gconf_audio_sink_init (GstGConfAudioSink * sink,
+ GstGConfAudioSinkClass * g_class)
+{
+ gst_gconf_audio_sink_reset (sink);
+
+ sink->client = gconf_client_get_default ();
+ gconf_client_add_dir (sink->client, GST_GCONF_DIR "/default",
+ GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+
+ gst_gconf_switch_profile (sink, GCONF_PROFILE_SOUNDS);
+}
+
+static void
+gst_gconf_audio_sink_dispose (GObject * object)
+{
+ GstGConfAudioSink *sink = GST_GCONF_AUDIO_SINK (object);
+
+ if (sink->client) {
+ gst_gconf_switch_profile (sink, GCONF_PROFILE_NONE);
+ g_object_unref (G_OBJECT (sink->client));
+ sink->client = NULL;
+ }
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static void
+gst_gconf_audio_sink_finalize (GstGConfAudioSink * sink)
+{
+ g_free (sink->gconf_str);
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, finalize, ((GObject *) (sink)));
+}
+
+static gboolean
+do_change_child (GstGConfAudioSink * sink)
+{
+ const gchar *key;
+ gchar *new_gconf_str;
+ GstElement *new_kid;
+
+ if (sink->profile == GCONF_PROFILE_NONE)
+ return FALSE; /* Can't switch to a 'NONE' sink */
+
+ key = gst_gconf_get_key_for_sink_profile (sink->profile);
+ new_gconf_str = gst_gconf_get_string (key);
+
+ GST_LOG_OBJECT (sink, "old gconf string: %s", GST_STR_NULL (sink->gconf_str));
+ GST_LOG_OBJECT (sink, "new gconf string: %s", GST_STR_NULL (new_gconf_str));
+
+ if (new_gconf_str != NULL && sink->gconf_str != NULL &&
+ (strlen (new_gconf_str) == 0 ||
+ strcmp (sink->gconf_str, new_gconf_str) == 0)) {
+ g_free (new_gconf_str);
+ GST_DEBUG_OBJECT (sink,
+ "GConf key was updated, but it didn't change. Ignoring");
+ return TRUE;
+ }
+
+ GST_DEBUG_OBJECT (sink, "GConf key changed: '%s' to '%s'",
+ GST_STR_NULL (sink->gconf_str), GST_STR_NULL (new_gconf_str));
+
+ GST_DEBUG_OBJECT (sink, "Creating new child for profile %d", sink->profile);
+ new_kid =
+ gst_gconf_render_bin_with_default (new_gconf_str, DEFAULT_AUDIOSINK);
+
+ if (new_kid == NULL) {
+ GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL),
+ ("Failed to render audio sink from GConf"));
+ goto fail;
+ }
+
+ if (!gst_switch_sink_set_child (GST_SWITCH_SINK (sink), new_kid)) {
+ GST_WARNING_OBJECT (sink, "Failed to update child element");
+ goto fail;
+ }
+
+ g_free (sink->gconf_str);
+ sink->gconf_str = new_gconf_str;
+
+ GST_DEBUG_OBJECT (sink, "done changing gconf audio sink");
+
+ return TRUE;
+
+fail:
+ g_free (new_gconf_str);
+ return FALSE;
+}
+
+static void
+gst_gconf_switch_profile (GstGConfAudioSink * sink, GstGConfProfile profile)
+{
+ if (sink->client == NULL)
+ return;
+
+ if (sink->notify_id) {
+ GST_DEBUG_OBJECT (sink, "Unsubscribing old key %s for profile %d",
+ gst_gconf_get_key_for_sink_profile (sink->profile), sink->profile);
+ gconf_client_notify_remove (sink->client, sink->notify_id);
+ sink->notify_id = 0;
+ }
+
+ sink->profile = profile;
+ if (profile != GCONF_PROFILE_NONE) {
+ const gchar *key = gst_gconf_get_key_for_sink_profile (sink->profile);
+
+ GST_DEBUG_OBJECT (sink, "Subscribing to key %s for profile %d",
+ key, profile);
+ sink->notify_id = gconf_client_notify_add (sink->client, key,
+ cb_change_child, sink, NULL, NULL);
+ }
+}
+
+static void
+gst_gconf_audio_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstGConfAudioSink *sink;
+
+ sink = GST_GCONF_AUDIO_SINK (object);
+
+ switch (prop_id) {
+ case PROP_PROFILE:
+ gst_gconf_switch_profile (sink, g_value_get_enum (value));
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_gconf_audio_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstGConfAudioSink *sink;
+
+ sink = GST_GCONF_AUDIO_SINK (object);
+
+ switch (prop_id) {
+ case PROP_PROFILE:
+ g_value_set_enum (value, sink->profile);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+cb_change_child (GConfClient * client,
+ guint connection_id, GConfEntry * entry, gpointer data)
+{
+ do_change_child (GST_GCONF_AUDIO_SINK (data));
+}
+
+static GstStateChangeReturn
+gst_gconf_audio_sink_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstGConfAudioSink *sink = GST_GCONF_AUDIO_SINK (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!do_change_child (sink)) {
+ gst_gconf_audio_sink_reset (sink);
+ return GST_STATE_CHANGE_FAILURE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
+ (element, transition), GST_STATE_CHANGE_SUCCESS);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ gst_gconf_audio_sink_reset (sink);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/gconf/gstgconfaudiosink.h b/ext/gconf/gstgconfaudiosink.h
new file mode 100644
index 0000000..2d730f3
--- /dev/null
+++ b/ext/gconf/gstgconfaudiosink.h
@@ -0,0 +1,62 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_GCONF_AUDIO_SINK_H__
+#define __GST_GCONF_AUDIO_SINK_H__
+
+#include <gst/gst.h>
+#include <gconf/gconf-client.h>
+#include "gstswitchsink.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GCONF_AUDIO_SINK \
+ (gst_gconf_audio_sink_get_type ())
+#define GST_GCONF_AUDIO_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GCONF_AUDIO_SINK, \
+ GstGConfAudioSink))
+#define GST_GCONF_AUDIO_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GCONF_AUDIO_SINK, \
+ GstGConfAudioSinkClass))
+#define GST_IS_GCONF_AUDIO_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GCONF_AUDIO_SINK))
+#define GST_IS_GCONF_AUDIO_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GCONF_AUDIO_SINK))
+
+typedef struct _GstGConfAudioSink {
+ GstSwitchSink parent;
+
+ /* explicit pointers to stuff used */
+ GConfClient *client;
+ GstGConfProfile profile;
+ guint notify_id;
+
+ /* Current gconf string */
+ gchar *gconf_str;
+} GstGConfAudioSink;
+
+typedef struct _GstGConfAudioSinkClass {
+ GstSwitchSinkClass parent_class;
+} GstGConfAudioSinkClass;
+
+GType gst_gconf_audio_sink_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_GCONF_AUDIO_SINK_H__ */
diff --git a/ext/gconf/gstgconfaudiosrc.c b/ext/gconf/gstgconfaudiosrc.c
new file mode 100644
index 0000000..2fdd61f
--- /dev/null
+++ b/ext/gconf/gstgconfaudiosrc.c
@@ -0,0 +1,210 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2005 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:element-gconfaudiosrc
+ * @see_also: #GstAlsaSrc, #GstAutoAudioSrc
+ *
+ * This element records sound from the audiosink that has been configured in
+ * GConf by the user.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch gconfaudiosrc ! audioconvert ! wavenc ! filesink location=record.wav
+ * ]| Record from configured audioinput
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstgconfelements.h"
+#include "gstgconfaudiosrc.h"
+
+static void gst_gconf_audio_src_dispose (GObject * object);
+static void gst_gconf_audio_src_finalize (GstGConfAudioSrc * src);
+static void cb_toggle_element (GConfClient * client,
+ guint connection_id, GConfEntry * entry, gpointer data);
+static GstStateChangeReturn
+gst_gconf_audio_src_change_state (GstElement * element,
+ GstStateChange transition);
+
+GST_BOILERPLATE (GstGConfAudioSrc, gst_gconf_audio_src, GstSwitchSrc,
+ GST_TYPE_SWITCH_SRC);
+
+static void
+gst_gconf_audio_src_base_init (gpointer klass)
+{
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_set_details_simple (eklass, "GConf audio source",
+ "Source/Audio",
+ "Audio source embedding the GConf-settings for audio input",
+ "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
+}
+
+static void
+gst_gconf_audio_src_class_init (GstGConfAudioSrcClass * klass)
+{
+ GObjectClass *oklass = G_OBJECT_CLASS (klass);
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ oklass->dispose = gst_gconf_audio_src_dispose;
+ oklass->finalize = (GObjectFinalizeFunc) gst_gconf_audio_src_finalize;
+ eklass->change_state = gst_gconf_audio_src_change_state;
+}
+
+/*
+ * Hack to make negotiation work.
+ */
+
+static gboolean
+gst_gconf_audio_src_reset (GstGConfAudioSrc * src)
+{
+ gst_switch_src_set_child (GST_SWITCH_SRC (src), NULL);
+
+ g_free (src->gconf_str);
+ src->gconf_str = NULL;
+ return TRUE;
+}
+
+static void
+gst_gconf_audio_src_init (GstGConfAudioSrc * src,
+ GstGConfAudioSrcClass * g_class)
+{
+ gst_gconf_audio_src_reset (src);
+
+ src->client = gconf_client_get_default ();
+ gconf_client_add_dir (src->client, GST_GCONF_DIR,
+ GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+ src->gconf_notify_id = gconf_client_notify_add (src->client,
+ GST_GCONF_DIR "/" GST_GCONF_AUDIOSRC_KEY,
+ cb_toggle_element, src, NULL, NULL);
+}
+
+static void
+gst_gconf_audio_src_dispose (GObject * object)
+{
+ GstGConfAudioSrc *src = GST_GCONF_AUDIO_SRC (object);
+
+ if (src->client) {
+ if (src->gconf_notify_id) {
+ gconf_client_notify_remove (src->client, src->gconf_notify_id);
+ src->gconf_notify_id = 0;
+ }
+
+ g_object_unref (G_OBJECT (src->client));
+ src->client = NULL;
+ }
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static void
+gst_gconf_audio_src_finalize (GstGConfAudioSrc * src)
+{
+ g_free (src->gconf_str);
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, finalize, ((GObject *) (src)));
+}
+
+static gboolean
+do_toggle_element (GstGConfAudioSrc * src)
+{
+ GstElement *new_kid;
+ gchar *new_gconf_str;
+
+ new_gconf_str = gst_gconf_get_string (GST_GCONF_AUDIOSRC_KEY);
+ if (new_gconf_str != NULL && src->gconf_str != NULL &&
+ (strlen (new_gconf_str) == 0 ||
+ strcmp (src->gconf_str, new_gconf_str) == 0)) {
+ g_free (new_gconf_str);
+ GST_DEBUG_OBJECT (src, "GConf key was updated, but it didn't change");
+ return TRUE;
+ }
+
+ GST_DEBUG_OBJECT (src, "GConf key changed: '%s' to '%s'",
+ GST_STR_NULL (src->gconf_str), GST_STR_NULL (new_gconf_str));
+
+ GST_DEBUG_OBJECT (src, "Creating new kid");
+ if (!(new_kid = gst_gconf_get_default_audio_src ())) {
+ GST_ELEMENT_ERROR (src, LIBRARY, SETTINGS, (NULL),
+ ("Failed to render audio src from GConf"));
+ return FALSE;
+ }
+
+ if (!gst_switch_src_set_child (GST_SWITCH_SRC (src), new_kid)) {
+ GST_WARNING_OBJECT (src, "Failed to update child element");
+ goto fail;
+ }
+
+ g_free (src->gconf_str);
+ src->gconf_str = new_gconf_str;
+
+ GST_DEBUG_OBJECT (src, "done changing gconf audio src");
+
+ return TRUE;
+fail:
+ g_free (new_gconf_str);
+ return FALSE;
+}
+
+static void
+cb_toggle_element (GConfClient * client,
+ guint connection_id, GConfEntry * entry, gpointer data)
+{
+ do_toggle_element (GST_GCONF_AUDIO_SRC (data));
+}
+
+static GstStateChangeReturn
+gst_gconf_audio_src_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstGConfAudioSrc *src = GST_GCONF_AUDIO_SRC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!do_toggle_element (src)) {
+ gst_gconf_audio_src_reset (src);
+ return GST_STATE_CHANGE_FAILURE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
+ (element, transition), GST_STATE_CHANGE_SUCCESS);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ if (!gst_gconf_audio_src_reset (src))
+ ret = GST_STATE_CHANGE_FAILURE;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/gconf/gstgconfaudiosrc.h b/ext/gconf/gstgconfaudiosrc.h
new file mode 100644
index 0000000..40fb94b
--- /dev/null
+++ b/ext/gconf/gstgconfaudiosrc.h
@@ -0,0 +1,57 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2005 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_GCONF_AUDIO_SRC_H__
+#define __GST_GCONF_AUDIO_SRC_H__
+
+#include <gst/gst.h>
+#include <gconf/gconf-client.h>
+
+#include "gstswitchsrc.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GCONF_AUDIO_SRC (gst_gconf_audio_src_get_type ())
+#define GST_GCONF_AUDIO_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GCONF_AUDIO_SRC, GstGConfAudioSrc))
+#define GST_GCONF_AUDIO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GCONF_AUDIO_SRC, GstGConfAudioSrcClass))
+#define GST_IS_GCONF_AUDIO_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GCONF_AUDIO_SRC))
+#define GST_IS_GCONF_AUDIO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GCONF_AUDIO_SRC))
+
+typedef struct _GstGConfAudioSrc {
+ GstSwitchSrc parent;
+
+ /* explicit pointers to stuff used */
+ GConfClient *client;
+
+ guint gconf_notify_id;
+
+ /* Current gconf string */
+ gchar *gconf_str;
+} GstGConfAudioSrc;
+
+typedef struct _GstGConfAudioSrcClass {
+ GstSwitchSrcClass parent_class;
+} GstGConfAudioSrcClass;
+
+GType gst_gconf_audio_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_GCONF_AUDIO_SRC_H__ */
diff --git a/ext/gconf/gstgconfelements.c b/ext/gconf/gstgconfelements.c
new file mode 100644
index 0000000..06f0113
--- /dev/null
+++ b/ext/gconf/gstgconfelements.c
@@ -0,0 +1,59 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "gstgconfelements.h"
+
+#include "gstgconfaudiosink.h"
+#include "gstgconfaudiosrc.h"
+#include "gstgconfvideosink.h"
+#include "gstgconfvideosrc.h"
+
+GST_DEBUG_CATEGORY (gconf_debug);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (gconf_debug, "gconf", 0,
+ "GConf/GStreamer audio/video output wrapper elements");
+
+ if (!gst_element_register (plugin, "gconfvideosink",
+ GST_RANK_NONE, GST_TYPE_GCONF_VIDEO_SINK) ||
+ !gst_element_register (plugin, "gconfvideosrc",
+ GST_RANK_NONE, GST_TYPE_GCONF_VIDEO_SRC) ||
+ !gst_element_register (plugin, "gconfaudiosink",
+ GST_RANK_NONE, GST_TYPE_GCONF_AUDIO_SINK) ||
+ !gst_element_register (plugin, "gconfaudiosrc",
+ GST_RANK_NONE, GST_TYPE_GCONF_AUDIO_SRC)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "gconfelements",
+ "elements wrapping the GStreamer/GConf audio/video output settings",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/gconf/gstgconfelements.h b/ext/gconf/gstgconfelements.h
new file mode 100644
index 0000000..872b2f2
--- /dev/null
+++ b/ext/gconf/gstgconfelements.h
@@ -0,0 +1,28 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_GCONF_ELEMENTS_H__
+#define __GST_GCONF_ELEMENTS_H__
+
+#include "gstgconf.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gconf_debug);
+#define GST_CAT_DEFAULT gconf_debug
+
+#endif /* __GST_GCONF_ELEMENTS_H__ */
diff --git a/ext/gconf/gstgconfvideosink.c b/ext/gconf/gstgconfvideosink.c
new file mode 100644
index 0000000..10fe90d
--- /dev/null
+++ b/ext/gconf/gstgconfvideosink.c
@@ -0,0 +1,210 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:element-gconfvideosink
+ *
+ * This element outputs video to the videosink that has been configured in
+ * GConf by the user.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch filesrc location=foo.ogg ! decodebin ! ffmpegcolorspace ! gconfvideosink
+ * ]| Play on configured videosink
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstgconfelements.h"
+#include "gstgconfvideosink.h"
+
+static void gst_gconf_video_sink_dispose (GObject * object);
+static void gst_gconf_video_sink_finalize (GstGConfVideoSink * sink);
+static void cb_toggle_element (GConfClient * client,
+ guint connection_id, GConfEntry * entry, gpointer data);
+static GstStateChangeReturn
+gst_gconf_video_sink_change_state (GstElement * element,
+ GstStateChange transition);
+
+GST_BOILERPLATE (GstGConfVideoSink, gst_gconf_video_sink, GstSwitchSink,
+ GST_TYPE_SWITCH_SINK);
+
+static void
+gst_gconf_video_sink_base_init (gpointer klass)
+{
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_set_details_simple (eklass, "GConf video sink",
+ "Sink/Video",
+ "Video sink embedding the GConf-settings for video output",
+ "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
+}
+
+static void
+gst_gconf_video_sink_class_init (GstGConfVideoSinkClass * klass)
+{
+ GObjectClass *oklass = G_OBJECT_CLASS (klass);
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ oklass->dispose = gst_gconf_video_sink_dispose;
+ oklass->finalize = (GObjectFinalizeFunc) gst_gconf_video_sink_finalize;
+ eklass->change_state = gst_gconf_video_sink_change_state;
+}
+
+/*
+ * Hack to make negotiation work.
+ */
+
+static void
+gst_gconf_video_sink_reset (GstGConfVideoSink * sink)
+{
+ gst_switch_sink_set_child (GST_SWITCH_SINK (sink), NULL);
+
+ g_free (sink->gconf_str);
+ sink->gconf_str = NULL;
+}
+
+static void
+gst_gconf_video_sink_init (GstGConfVideoSink * sink,
+ GstGConfVideoSinkClass * g_class)
+{
+ gst_gconf_video_sink_reset (sink);
+
+ sink->client = gconf_client_get_default ();
+ gconf_client_add_dir (sink->client, GST_GCONF_DIR,
+ GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+ sink->notify_id = gconf_client_notify_add (sink->client,
+ GST_GCONF_DIR "/" GST_GCONF_VIDEOSINK_KEY,
+ cb_toggle_element, sink, NULL, NULL);
+}
+
+static void
+gst_gconf_video_sink_dispose (GObject * object)
+{
+ GstGConfVideoSink *sink = GST_GCONF_VIDEO_SINK (object);
+
+ if (sink->client) {
+ if (sink->notify_id != 0)
+ gconf_client_notify_remove (sink->client, sink->notify_id);
+
+ g_object_unref (G_OBJECT (sink->client));
+ sink->client = NULL;
+ }
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static void
+gst_gconf_video_sink_finalize (GstGConfVideoSink * sink)
+{
+ g_free (sink->gconf_str);
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, finalize, ((GObject *) (sink)));
+}
+
+static gboolean
+do_change_child (GstGConfVideoSink * sink)
+{
+ gchar *new_gconf_str;
+ GstElement *new_kid;
+
+ new_gconf_str = gst_gconf_get_string (GST_GCONF_VIDEOSINK_KEY);
+
+ GST_LOG_OBJECT (sink, "old gconf string: %s", GST_STR_NULL (sink->gconf_str));
+ GST_LOG_OBJECT (sink, "new gconf string: %s", GST_STR_NULL (new_gconf_str));
+
+ if (new_gconf_str != NULL && sink->gconf_str != NULL &&
+ (strlen (new_gconf_str) == 0 ||
+ strcmp (sink->gconf_str, new_gconf_str) == 0)) {
+ g_free (new_gconf_str);
+ GST_DEBUG_OBJECT (sink,
+ "GConf key was updated, but it didn't change. Ignoring");
+ return TRUE;
+ }
+
+ GST_DEBUG_OBJECT (sink, "GConf key changed: '%s' to '%s'",
+ GST_STR_NULL (sink->gconf_str), GST_STR_NULL (new_gconf_str));
+
+ GST_DEBUG_OBJECT (sink, "Creating new kid");
+ if (!(new_kid = gst_gconf_get_default_video_sink ())) {
+ GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL),
+ ("Failed to render video sink from GConf"));
+ return FALSE;
+ }
+
+ if (!gst_switch_sink_set_child (GST_SWITCH_SINK (sink), new_kid)) {
+ GST_WARNING_OBJECT (sink, "Failed to update child element");
+ goto fail;
+ }
+
+ g_free (sink->gconf_str);
+ sink->gconf_str = new_gconf_str;
+
+ GST_DEBUG_OBJECT (sink, "done changing gconf video sink");
+
+ return TRUE;
+
+fail:
+ g_free (new_gconf_str);
+ return FALSE;
+}
+
+static void
+cb_toggle_element (GConfClient * client,
+ guint connection_id, GConfEntry * entry, gpointer data)
+{
+ do_change_child (GST_GCONF_VIDEO_SINK (data));
+}
+
+static GstStateChangeReturn
+gst_gconf_video_sink_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstGConfVideoSink *sink = GST_GCONF_VIDEO_SINK (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!do_change_child (sink)) {
+ gst_gconf_video_sink_reset (sink);
+ return GST_STATE_CHANGE_FAILURE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
+ (element, transition), GST_STATE_CHANGE_SUCCESS);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ gst_gconf_video_sink_reset (sink);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/gconf/gstgconfvideosink.h b/ext/gconf/gstgconfvideosink.h
new file mode 100644
index 0000000..faaa0a8
--- /dev/null
+++ b/ext/gconf/gstgconfvideosink.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_GCONF_VIDEO_SINK_H__
+#define __GST_GCONF_VIDEO_SINK_H__
+
+#include <gst/gst.h>
+#include <gconf/gconf-client.h>
+
+#include "gstswitchsink.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GCONF_VIDEO_SINK \
+ (gst_gconf_video_sink_get_type ())
+#define GST_GCONF_VIDEO_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GCONF_VIDEO_SINK, \
+ GstGConfVideoSink))
+#define GST_GCONF_VIDEO_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GCONF_VIDEO_SINK, \
+ GstGConfVideoSinkClass))
+#define GST_IS_GCONF_VIDEO_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GCONF_VIDEO_SINK))
+#define GST_IS_GCONF_VIDEO_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GCONF_VIDEO_SINK))
+
+typedef struct _GstGConfVideoSink {
+ GstSwitchSink parent;
+
+ /* explicit pointers to stuff used */
+ GConfClient *client;
+
+ /* gconf notify id */
+ guint notify_id;
+
+ /* Current gconf string */
+ gchar *gconf_str;
+} GstGConfVideoSink;
+
+typedef struct _GstGConfVideoSinkClass {
+ GstSwitchSinkClass parent_class;
+} GstGConfVideoSinkClass;
+
+GType gst_gconf_video_sink_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_GCONF_VIDEO_SINK_H__ */
diff --git a/ext/gconf/gstgconfvideosrc.c b/ext/gconf/gstgconfvideosrc.c
new file mode 100644
index 0000000..2d9d5df
--- /dev/null
+++ b/ext/gconf/gstgconfvideosrc.c
@@ -0,0 +1,209 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2005 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:element-gconfvideosrc
+ * @see_also: #GstAlsaSrc, #GstAutoVideoSrc
+ *
+ * This element records video from the videosink that has been configured in
+ * GConf by the user.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch gconfvideosrc ! theoraenc ! oggmux ! filesink location=record.ogg
+ * ]| Record from configured videoinput
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstgconfelements.h"
+#include "gstgconfvideosrc.h"
+
+static void gst_gconf_video_src_dispose (GObject * object);
+static void gst_gconf_video_src_finalize (GstGConfVideoSrc * src);
+static void cb_toggle_element (GConfClient * client,
+ guint connection_id, GConfEntry * entry, gpointer data);
+static GstStateChangeReturn
+gst_gconf_video_src_change_state (GstElement * element,
+ GstStateChange transition);
+
+GST_BOILERPLATE (GstGConfVideoSrc, gst_gconf_video_src, GstSwitchSrc,
+ GST_TYPE_SWITCH_SRC);
+
+static void
+gst_gconf_video_src_base_init (gpointer klass)
+{
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_set_details_simple (eklass, "GConf video source",
+ "Source/Video",
+ "Video source embedding the GConf-settings for video input",
+ "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
+}
+
+static void
+gst_gconf_video_src_class_init (GstGConfVideoSrcClass * klass)
+{
+ GObjectClass *oklass = G_OBJECT_CLASS (klass);
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ oklass->dispose = gst_gconf_video_src_dispose;
+ oklass->finalize = (GObjectFinalizeFunc) gst_gconf_video_src_finalize;
+ eklass->change_state = gst_gconf_video_src_change_state;
+}
+
+/*
+ * Hack to make negotiation work.
+ */
+
+static gboolean
+gst_gconf_video_src_reset (GstGConfVideoSrc * src)
+{
+ gst_switch_src_set_child (GST_SWITCH_SRC (src), NULL);
+
+ g_free (src->gconf_str);
+ src->gconf_str = NULL;
+
+ return TRUE;
+}
+
+static void
+gst_gconf_video_src_init (GstGConfVideoSrc * src,
+ GstGConfVideoSrcClass * g_class)
+{
+ gst_gconf_video_src_reset (src);
+
+ src->client = gconf_client_get_default ();
+ gconf_client_add_dir (src->client, GST_GCONF_DIR,
+ GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+ src->notify_id = gconf_client_notify_add (src->client,
+ GST_GCONF_DIR "/" GST_GCONF_VIDEOSRC_KEY,
+ cb_toggle_element, src, NULL, NULL);
+}
+
+static void
+gst_gconf_video_src_dispose (GObject * object)
+{
+ GstGConfVideoSrc *src = GST_GCONF_VIDEO_SRC (object);
+
+ if (src->client) {
+ if (src->notify_id != 0)
+ gconf_client_notify_remove (src->client, src->notify_id);
+
+ g_object_unref (G_OBJECT (src->client));
+ src->client = NULL;
+ }
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static void
+gst_gconf_video_src_finalize (GstGConfVideoSrc * src)
+{
+ g_free (src->gconf_str);
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, finalize, ((GObject *) (src)));
+}
+
+static gboolean
+do_toggle_element (GstGConfVideoSrc * src)
+{
+ GstElement *new_kid;
+ gchar *new_gconf_str;
+
+ new_gconf_str = gst_gconf_get_string (GST_GCONF_VIDEOSRC_KEY);
+ if (new_gconf_str != NULL && src->gconf_str != NULL &&
+ (strlen (new_gconf_str) == 0 ||
+ strcmp (src->gconf_str, new_gconf_str) == 0)) {
+ g_free (new_gconf_str);
+ GST_DEBUG_OBJECT (src, "GConf key was updated, but it didn't change");
+ return TRUE;
+ }
+
+ GST_DEBUG_OBJECT (src, "GConf key changed: '%s' to '%s'",
+ GST_STR_NULL (src->gconf_str), GST_STR_NULL (new_gconf_str));
+
+ GST_DEBUG_OBJECT (src, "Creating new kid");
+ if (!(new_kid = gst_gconf_get_default_video_src ())) {
+ GST_ELEMENT_ERROR (src, LIBRARY, SETTINGS, (NULL),
+ ("Failed to render video src from GConf"));
+ return FALSE;
+ }
+
+ if (!gst_switch_src_set_child (GST_SWITCH_SRC (src), new_kid)) {
+ GST_WARNING_OBJECT (src, "Failed to update child element");
+ goto fail;
+ }
+
+ g_free (src->gconf_str);
+ src->gconf_str = new_gconf_str;
+
+ GST_DEBUG_OBJECT (src, "done changing gconf video src");
+
+ return TRUE;
+fail:
+ g_free (new_gconf_str);
+ return FALSE;
+}
+
+static void
+cb_toggle_element (GConfClient * client,
+ guint connection_id, GConfEntry * entry, gpointer data)
+{
+ do_toggle_element (GST_GCONF_VIDEO_SRC (data));
+}
+
+static GstStateChangeReturn
+gst_gconf_video_src_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstGConfVideoSrc *src = GST_GCONF_VIDEO_SRC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!do_toggle_element (src)) {
+ gst_gconf_video_src_reset (src);
+ return GST_STATE_CHANGE_FAILURE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
+ (element, transition), GST_STATE_CHANGE_SUCCESS);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ if (!gst_gconf_video_src_reset (src))
+ ret = GST_STATE_CHANGE_FAILURE;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/gconf/gstgconfvideosrc.h b/ext/gconf/gstgconfvideosrc.h
new file mode 100644
index 0000000..5c8300d
--- /dev/null
+++ b/ext/gconf/gstgconfvideosrc.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2005 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_GCONF_VIDEO_SRC_H__
+#define __GST_GCONF_VIDEO_SRC_H__
+
+#include <gst/gst.h>
+#include <gconf/gconf-client.h>
+
+#include "gstswitchsrc.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GCONF_VIDEO_SRC (gst_gconf_video_src_get_type ())
+#define GST_GCONF_VIDEO_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GCONF_VIDEO_SRC, GstGConfVideoSrc))
+#define GST_GCONF_VIDEO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GCONF_VIDEO_SRC, GstGConfVideoSrcClass))
+#define GST_IS_GCONF_VIDEO_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GCONF_VIDEO_SRC))
+#define GST_IS_GCONF_VIDEO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GCONF_VIDEO_SRC))
+
+typedef struct _GstGConfVideoSrc {
+ GstSwitchSrc parent;
+
+ /* explicit pointers to stuff used */
+ GConfClient *client;
+
+ /* gconf key notification id */
+ guint notify_id;
+
+ /* Current gconf string */
+ gchar *gconf_str;
+} GstGConfVideoSrc;
+
+typedef struct _GstGConfVideoSrcClass {
+ GstSwitchSrcClass parent_class;
+} GstGConfVideoSrcClass;
+
+GType gst_gconf_video_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_GCONF_VIDEO_SRC_H__ */
diff --git a/ext/gconf/gstswitchsink.c b/ext/gconf/gstswitchsink.c
new file mode 100644
index 0000000..da31df2
--- /dev/null
+++ b/ext/gconf/gstswitchsink.c
@@ -0,0 +1,269 @@
+/* GStreamer
+ * Copyright (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * Copyright (c) 2006 Jürg Billeter <j@bitron.ch>
+ * Copyright (c) 2007 Jan Schmidt <thaytan@noraisin.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstswitchsink.h"
+
+GST_DEBUG_CATEGORY_STATIC (switch_debug);
+#define GST_CAT_DEFAULT switch_debug
+
+static void gst_switch_sink_dispose (GObject * object);
+static GstStateChangeReturn
+gst_switch_sink_change_state (GstElement * element, GstStateChange transition);
+
+enum
+{
+ PROP_0
+};
+
+GST_BOILERPLATE (GstSwitchSink, gst_switch_sink, GstBin, GST_TYPE_BIN);
+
+static void
+gst_switch_sink_base_init (gpointer klass)
+{
+ GST_DEBUG_CATEGORY_INIT (switch_debug, "switchsink", 0, "switchsink element");
+}
+
+static void
+gst_switch_sink_class_init (GstSwitchSinkClass * klass)
+{
+ GObjectClass *oklass = G_OBJECT_CLASS (klass);
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+ GstPadTemplate *child_pad_templ;
+
+ oklass->dispose = gst_switch_sink_dispose;
+ eklass->change_state = gst_switch_sink_change_state;
+
+ /* Provide a default pad template if the child didn't */
+ child_pad_templ = gst_element_class_get_pad_template (eklass, "sink");
+ if (child_pad_templ == NULL) {
+ gst_element_class_add_static_pad_template (eklass, &sink_template);
+ }
+}
+
+static gboolean
+gst_switch_sink_reset (GstSwitchSink * sink)
+{
+ /* this will install fakesink if no other child has been set,
+ * otherwise we rely on the subclass to know when to unset its
+ * custom kid */
+ if (sink->kid == NULL) {
+ return gst_switch_sink_set_child (sink, NULL);
+ }
+
+ return TRUE;
+}
+
+static void
+gst_switch_sink_init (GstSwitchSink * sink, GstSwitchSinkClass * g_class)
+{
+ GstElementClass *eklass = GST_ELEMENT_GET_CLASS (sink);
+ GstPadTemplate *templ;
+
+ templ = gst_element_class_get_pad_template (eklass, "sink");
+ sink->pad = gst_ghost_pad_new_no_target_from_template ("sink", templ);
+ gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
+
+ gst_switch_sink_reset (sink);
+
+ GST_OBJECT_FLAG_SET (sink, GST_ELEMENT_IS_SINK);
+}
+
+static void
+gst_switch_sink_dispose (GObject * object)
+{
+ GstSwitchSink *sink = GST_SWITCH_SINK (object);
+ GstObject *new_kid, *kid;
+
+ GST_OBJECT_LOCK (sink);
+ new_kid = GST_OBJECT_CAST (sink->new_kid);
+ sink->new_kid = NULL;
+
+ kid = GST_OBJECT_CAST (sink->kid);
+ sink->kid = NULL;
+ GST_OBJECT_UNLOCK (sink);
+
+ gst_object_replace (&new_kid, NULL);
+ gst_object_replace (&kid, NULL);
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static gboolean
+gst_switch_sink_commit_new_kid (GstSwitchSink * sink)
+{
+ GstPad *targetpad;
+ GstState kid_state;
+ GstElement *new_kid, *old_kid;
+ gboolean is_fakesink = FALSE;
+ GstBus *bus;
+
+ /* need locking around member accesses */
+ GST_OBJECT_LOCK (sink);
+ /* If we're currently changing state, set the child to the next state
+ * we're transitioning too, rather than our current state which is
+ * about to change */
+ if (GST_STATE_NEXT (sink) != GST_STATE_VOID_PENDING)
+ kid_state = GST_STATE_NEXT (sink);
+ else
+ kid_state = GST_STATE (sink);
+
+ new_kid = sink->new_kid ? gst_object_ref (sink->new_kid) : NULL;
+ sink->new_kid = NULL;
+ GST_OBJECT_UNLOCK (sink);
+
+ /* Fakesink by default if NULL is passed as the new child */
+ if (new_kid == NULL) {
+ GST_DEBUG_OBJECT (sink, "Replacing kid with fakesink");
+ new_kid = gst_element_factory_make ("fakesink", "testsink");
+ if (new_kid == NULL) {
+ GST_ERROR_OBJECT (sink, "Failed to create fakesink");
+ return FALSE;
+ }
+ /* Add a reference, as it would if the element came from sink->new_kid */
+ gst_object_ref (new_kid);
+ g_object_set (new_kid, "sync", TRUE, NULL);
+ is_fakesink = TRUE;
+ } else {
+ GST_DEBUG_OBJECT (sink, "Setting new kid");
+ }
+
+ /* set temporary bus of our own to catch error messages from the child
+ * (could we just set our own bus on it, or would the state change messages
+ * from the not-yet-added element confuse the state change algorithm? Let's
+ * play it safe for now) */
+ bus = gst_bus_new ();
+ gst_element_set_bus (new_kid, bus);
+ gst_object_unref (bus);
+
+ if (gst_element_set_state (new_kid, kid_state) == GST_STATE_CHANGE_FAILURE) {
+ GstMessage *msg;
+
+ /* check if child posted an error message and if so re-post it on our bus
+ * so that the application gets to see a decent error and not our generic
+ * fallback error message which is completely indecipherable to the user */
+ msg = gst_bus_pop_filtered (GST_ELEMENT_BUS (new_kid), GST_MESSAGE_ERROR);
+ if (msg) {
+ GST_INFO_OBJECT (sink, "Forwarding kid error: %" GST_PTR_FORMAT, msg);
+ gst_element_post_message (GST_ELEMENT (sink), msg);
+ }
+ GST_ELEMENT_ERROR (sink, CORE, STATE_CHANGE, (NULL),
+ ("Failed to set state on new child."));
+ gst_element_set_bus (new_kid, NULL);
+ gst_object_unref (new_kid);
+ return FALSE;
+ }
+ gst_element_set_bus (new_kid, NULL);
+ gst_bin_add (GST_BIN (sink), new_kid);
+
+ /* Now, replace the existing child */
+ GST_OBJECT_LOCK (sink);
+ old_kid = sink->kid;
+ sink->kid = new_kid;
+ /* Mark whether a custom kid or fakesink has been installed */
+ sink->have_kid = !is_fakesink;
+ GST_OBJECT_UNLOCK (sink);
+
+ /* kill old element */
+ if (old_kid) {
+ GST_DEBUG_OBJECT (sink, "Removing old kid %" GST_PTR_FORMAT, old_kid);
+ gst_element_set_state (old_kid, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN (sink), old_kid);
+ gst_object_unref (old_kid);
+ /* Don't lose the SINK flag */
+ GST_OBJECT_FLAG_SET (sink, GST_ELEMENT_IS_SINK);
+ }
+
+ /* re-attach ghostpad */
+ GST_DEBUG_OBJECT (sink, "Creating new ghostpad");
+ targetpad = gst_element_get_static_pad (sink->kid, "sink");
+ gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
+ gst_object_unref (targetpad);
+ GST_DEBUG_OBJECT (sink, "done changing child of switchsink");
+
+ /* FIXME: Push new-segment info and pre-roll buffer(s) into the kid */
+
+ return TRUE;
+}
+
+gboolean
+gst_switch_sink_set_child (GstSwitchSink * sink, GstElement * new_kid)
+{
+ GstState cur, next;
+ GstElement **p_kid;
+
+ /* Nothing to do if clearing the child and we've already installed fakesink */
+ if (new_kid == NULL && sink->kid != NULL && sink->have_kid == FALSE)
+ return TRUE;
+
+ /* Store the new kid to be committed later */
+ GST_OBJECT_LOCK (sink);
+ cur = GST_STATE (sink);
+ next = GST_STATE_NEXT (sink);
+ p_kid = &sink->new_kid;
+ gst_object_replace ((GstObject **) p_kid, (GstObject *) new_kid);
+ GST_OBJECT_UNLOCK (sink);
+ if (new_kid)
+ gst_object_unref (new_kid);
+
+ /* Sometime, it would be lovely to allow sink changes even when
+ * already running, but this involves sending an appropriate new-segment
+ * and possibly prerolling etc */
+ /* FIXME: Block the pad and replace the kid when it completes */
+ if (cur > GST_STATE_READY || next == GST_STATE_PAUSED) {
+ GST_DEBUG_OBJECT (sink,
+ "Switch-sink is already running. Ignoring change of child.");
+ gst_object_unref (new_kid);
+ return TRUE;
+ }
+
+ return gst_switch_sink_commit_new_kid (sink);
+}
+
+static GstStateChangeReturn
+gst_switch_sink_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstSwitchSink *sink = GST_SWITCH_SINK (element);
+
+ ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
+ (element, transition), GST_STATE_CHANGE_SUCCESS);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ if (!gst_switch_sink_reset (sink))
+ ret = GST_STATE_CHANGE_FAILURE;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/gconf/gstswitchsink.h b/ext/gconf/gstswitchsink.h
new file mode 100644
index 0000000..556e755
--- /dev/null
+++ b/ext/gconf/gstswitchsink.h
@@ -0,0 +1,62 @@
+/* GStreamer
+ * Copyright (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * Copyright (c) 2007 Jan Schmidt <thaytan@mad.scientist.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_SWITCH_SINK_H__
+#define __GST_SWITCH_SINK_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SWITCH_SINK \
+ (gst_switch_sink_get_type ())
+#define GST_SWITCH_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SWITCH_SINK, \
+ GstSwitchSink))
+#define GST_SWITCH_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SWITCH_SINK, \
+ GstSwitchSinkClass))
+#define GST_IS_SWITCH_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SWITCH_SINK))
+#define GST_IS_SWITCH_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SWITCH_SINK))
+
+typedef struct _GstSwitchSink {
+ GstBin parent;
+
+ GstElement *kid;
+ GstElement *new_kid;
+ GstPad *pad;
+
+ /* If a custom child has been set... */
+ gboolean have_kid;
+} GstSwitchSink;
+
+typedef struct _GstSwitchSinkClass {
+ GstBinClass parent_class;
+} GstSwitchSinkClass;
+
+GType gst_switch_sink_get_type (void);
+
+gboolean gst_switch_sink_set_child (GstSwitchSink *ssink, GstElement *new_kid);
+
+G_END_DECLS
+
+#endif /* __GST_SWITCH_SINK_H__ */
diff --git a/ext/gconf/gstswitchsrc.c b/ext/gconf/gstswitchsrc.c
new file mode 100644
index 0000000..664e0bd
--- /dev/null
+++ b/ext/gconf/gstswitchsrc.c
@@ -0,0 +1,261 @@
+/* GStreamer
+ * Copyright (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * Copyright (c) 2006 Jürg Billeter <j@bitron.ch>
+ * Copyright (c) 2007 Jan Schmidt <thaytan@noraisin.net>
+ * Copyright (c) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstswitchsrc.h"
+
+GST_DEBUG_CATEGORY_STATIC (switch_debug);
+#define GST_CAT_DEFAULT switch_debug
+
+static void gst_switch_src_dispose (GObject * object);
+static GstStateChangeReturn
+gst_switch_src_change_state (GstElement * element, GstStateChange transition);
+
+GST_BOILERPLATE (GstSwitchSrc, gst_switch_src, GstBin, GST_TYPE_BIN);
+
+static void
+gst_switch_src_base_init (gpointer klass)
+{
+ GST_DEBUG_CATEGORY_INIT (switch_debug, "switchsrc", 0, "switchsrc element");
+}
+
+static void
+gst_switch_src_class_init (GstSwitchSrcClass * klass)
+{
+ GObjectClass *oklass = G_OBJECT_CLASS (klass);
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+ GstPadTemplate *child_pad_templ;
+
+ oklass->dispose = gst_switch_src_dispose;
+ eklass->change_state = gst_switch_src_change_state;
+
+ /* Provide a default pad template if the child didn't */
+ child_pad_templ = gst_element_class_get_pad_template (eklass, "src");
+ if (child_pad_templ == NULL) {
+ gst_element_class_add_static_pad_template (eklass, &src_template);
+ }
+}
+
+static gboolean
+gst_switch_src_reset (GstSwitchSrc * src)
+{
+ /* this will install fakesrc if no other child has been set,
+ * otherwise we rely on the subclass to know when to unset its
+ * custom kid */
+ if (src->kid == NULL) {
+ return gst_switch_src_set_child (src, NULL);
+ }
+
+ return TRUE;
+}
+
+static void
+gst_switch_src_init (GstSwitchSrc * src, GstSwitchSrcClass * g_class)
+{
+ GstElementClass *eklass = GST_ELEMENT_GET_CLASS (src);
+ GstPadTemplate *templ;
+
+ templ = gst_element_class_get_pad_template (eklass, "src");
+ src->pad = gst_ghost_pad_new_no_target_from_template ("src", templ);
+ gst_element_add_pad (GST_ELEMENT (src), src->pad);
+
+ gst_switch_src_reset (src);
+
+ GST_OBJECT_FLAG_SET (src, GST_ELEMENT_IS_SOURCE);
+}
+
+static void
+gst_switch_src_dispose (GObject * object)
+{
+ GstSwitchSrc *src = GST_SWITCH_SRC (object);
+ GstObject *new_kid, *kid;
+
+ GST_OBJECT_LOCK (src);
+ new_kid = GST_OBJECT_CAST (src->new_kid);
+ src->new_kid = NULL;
+
+ kid = GST_OBJECT_CAST (src->kid);
+ src->kid = NULL;
+ GST_OBJECT_UNLOCK (src);
+
+ gst_object_replace (&new_kid, NULL);
+ gst_object_replace (&kid, NULL);
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static gboolean
+gst_switch_src_commit_new_kid (GstSwitchSrc * src)
+{
+ GstPad *targetpad;
+ GstState kid_state;
+ GstElement *new_kid, *old_kid;
+ gboolean is_fakesrc = FALSE;
+ GstBus *bus;
+
+ /* need locking around member accesses */
+ GST_OBJECT_LOCK (src);
+ /* If we're currently changing state, set the child to the next state
+ * we're transitioning too, rather than our current state which is
+ * about to change */
+ if (GST_STATE_NEXT (src) != GST_STATE_VOID_PENDING)
+ kid_state = GST_STATE_NEXT (src);
+ else
+ kid_state = GST_STATE (src);
+
+ new_kid = src->new_kid ? gst_object_ref (src->new_kid) : NULL;
+ src->new_kid = NULL;
+ GST_OBJECT_UNLOCK (src);
+
+ /* Fakesrc by default if NULL is passed as the new child */
+ if (new_kid == NULL) {
+ GST_DEBUG_OBJECT (src, "Replacing kid with fakesrc");
+ new_kid = gst_element_factory_make ("fakesrc", "testsrc");
+ if (new_kid == NULL) {
+ GST_ERROR_OBJECT (src, "Failed to create fakesrc");
+ return FALSE;
+ }
+ /* Add a reference, as it would if the element came from src->new_kid */
+ gst_object_ref (new_kid);
+ is_fakesrc = TRUE;
+ } else {
+ GST_DEBUG_OBJECT (src, "Setting new kid");
+ }
+
+ /* set temporary bus of our own to catch error messages from the child
+ * (could we just set our own bus on it, or would the state change messages
+ * from the not-yet-added element confuse the state change algorithm? Let's
+ * play it safe for now) */
+ bus = gst_bus_new ();
+ gst_element_set_bus (new_kid, bus);
+ gst_object_unref (bus);
+
+ if (gst_element_set_state (new_kid, kid_state) == GST_STATE_CHANGE_FAILURE) {
+ GstMessage *msg;
+
+ /* check if child posted an error message and if so re-post it on our bus
+ * so that the application gets to see a decent error and not our generic
+ * fallback error message which is completely indecipherable to the user */
+ msg = gst_bus_pop_filtered (GST_ELEMENT_BUS (new_kid), GST_MESSAGE_ERROR);
+ if (msg) {
+ GST_INFO_OBJECT (src, "Forwarding kid error: %" GST_PTR_FORMAT, msg);
+ gst_element_post_message (GST_ELEMENT (src), msg);
+ }
+ GST_ELEMENT_ERROR (src, CORE, STATE_CHANGE, (NULL),
+ ("Failed to set state on new child."));
+ gst_element_set_bus (new_kid, NULL);
+ gst_object_unref (new_kid);
+ return FALSE;
+ }
+ gst_element_set_bus (new_kid, NULL);
+ gst_bin_add (GST_BIN (src), new_kid);
+
+ /* Now, replace the existing child */
+ GST_OBJECT_LOCK (src);
+ old_kid = src->kid;
+ src->kid = new_kid;
+ /* Mark whether a custom kid or fakesrc has been installed */
+ src->have_kid = !is_fakesrc;
+ GST_OBJECT_UNLOCK (src);
+
+ /* kill old element */
+ if (old_kid) {
+ GST_DEBUG_OBJECT (src, "Removing old kid %" GST_PTR_FORMAT, old_kid);
+ gst_element_set_state (old_kid, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN (src), old_kid);
+ gst_object_unref (old_kid);
+ /* Don't lose the SOURCE flag */
+ GST_OBJECT_FLAG_SET (src, GST_ELEMENT_IS_SOURCE);
+ }
+
+ /* re-attach ghostpad */
+ GST_DEBUG_OBJECT (src, "Creating new ghostpad");
+ targetpad = gst_element_get_static_pad (src->kid, "src");
+ gst_ghost_pad_set_target (GST_GHOST_PAD (src->pad), targetpad);
+ gst_object_unref (targetpad);
+ GST_DEBUG_OBJECT (src, "done changing child of switchsrc");
+
+ return TRUE;
+}
+
+gboolean
+gst_switch_src_set_child (GstSwitchSrc * src, GstElement * new_kid)
+{
+ GstState cur, next;
+ GstElement **p_kid;
+
+ /* Nothing to do if clearing the child and we've already installed fakesrc */
+ if (new_kid == NULL && src->kid != NULL && src->have_kid == FALSE)
+ return TRUE;
+
+ /* Store the new kid to be committed later */
+ GST_OBJECT_LOCK (src);
+ cur = GST_STATE (src);
+ next = GST_STATE_NEXT (src);
+ p_kid = &src->new_kid;
+ gst_object_replace ((GstObject **) p_kid, (GstObject *) new_kid);
+ GST_OBJECT_UNLOCK (src);
+ if (new_kid)
+ gst_object_unref (new_kid);
+
+ /* Sometime, it would be lovely to allow src changes even when
+ * already running */
+ /* FIXME: Block the pad and replace the kid when it completes */
+ if (cur > GST_STATE_READY || next == GST_STATE_PAUSED) {
+ GST_DEBUG_OBJECT (src,
+ "Switch-src is already running. Ignoring change of child.");
+ gst_object_unref (new_kid);
+ return TRUE;
+ }
+
+ return gst_switch_src_commit_new_kid (src);
+}
+
+static GstStateChangeReturn
+gst_switch_src_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstSwitchSrc *src = GST_SWITCH_SRC (element);
+
+ ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
+ (element, transition), GST_STATE_CHANGE_SUCCESS);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ if (!gst_switch_src_reset (src))
+ ret = GST_STATE_CHANGE_FAILURE;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/gconf/gstswitchsrc.h b/ext/gconf/gstswitchsrc.h
new file mode 100644
index 0000000..6c550ad
--- /dev/null
+++ b/ext/gconf/gstswitchsrc.h
@@ -0,0 +1,57 @@
+/* GStreamer
+ *
+ * Copyright (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * Copyright (c) 2005 Tim-Philipp Müller <tim centricular net>
+ * Copyright (c) 2007 Jan Schmidt <thaytan@mad.scientist.com>
+ * Copyright (c) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_SWITCH_SRC_H__
+#define __GST_SWITCH_SRC_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SWITCH_SRC (gst_switch_src_get_type ())
+#define GST_SWITCH_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SWITCH_SRC, GstSwitchSrc))
+#define GST_SWITCH_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SWITCH_SRC, GstSwitchSrcClass))
+#define GST_IS_SWITCH_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SWITCH_SRC))
+#define GST_IS_SWITCH_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SWITCH_SRC))
+
+typedef struct _GstSwitchSrc {
+ GstBin parent;
+
+ GstElement *kid;
+ GstElement *new_kid;
+ GstPad *pad;
+
+ /* If a custom child has been set... */
+ gboolean have_kid;
+} GstSwitchSrc;
+
+typedef struct _GstSwitchSrcClass {
+ GstBinClass parent_class;
+} GstSwitchSrcClass;
+
+GType gst_switch_src_get_type (void);
+gboolean gst_switch_src_set_child (GstSwitchSrc *ssrc, GstElement *new_kid);
+
+G_END_DECLS
+
+#endif /* __GST_SWITCH_SRC_H__ */
diff --git a/ext/gdk_pixbuf/Makefile.am b/ext/gdk_pixbuf/Makefile.am
new file mode 100644
index 0000000..cf5265c
--- /dev/null
+++ b/ext/gdk_pixbuf/Makefile.am
@@ -0,0 +1,19 @@
+plugin_LTLIBRARIES = libgstgdkpixbuf.la
+
+libgstgdkpixbuf_la_SOURCES = gstgdkpixbuf.c gstgdkpixbufsink.c pixbufscale.c
+libgstgdkpixbuf_la_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) $(GDK_PIXBUF_CFLAGS)
+libgstgdkpixbuf_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS) $(GDK_PIXBUF_LIBS)
+libgstgdkpixbuf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstgdkpixbuf_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = \
+ gstgdkpixbuf.h \
+ gstgdkpixbufsink.h \
+ pixbufscale.h \
+ gstgdkanimation.h
diff --git a/ext/gdk_pixbuf/Makefile.in b/ext/gdk_pixbuf/Makefile.in
new file mode 100644
index 0000000..72f8caa
--- /dev/null
+++ b/ext/gdk_pixbuf/Makefile.in
@@ -0,0 +1,837 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/gdk_pixbuf
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstgdkpixbuf_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgstgdkpixbuf_la_OBJECTS = libgstgdkpixbuf_la-gstgdkpixbuf.lo \
+ libgstgdkpixbuf_la-gstgdkpixbufsink.lo \
+ libgstgdkpixbuf_la-pixbufscale.lo
+libgstgdkpixbuf_la_OBJECTS = $(am_libgstgdkpixbuf_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstgdkpixbuf_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstgdkpixbuf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstgdkpixbuf_la_CFLAGS) $(CFLAGS) \
+ $(libgstgdkpixbuf_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstgdkpixbuf_la_SOURCES)
+DIST_SOURCES = $(libgstgdkpixbuf_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstgdkpixbuf.la
+libgstgdkpixbuf_la_SOURCES = gstgdkpixbuf.c gstgdkpixbufsink.c pixbufscale.c
+libgstgdkpixbuf_la_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) $(GDK_PIXBUF_CFLAGS)
+
+libgstgdkpixbuf_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS) $(GDK_PIXBUF_LIBS)
+
+libgstgdkpixbuf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstgdkpixbuf_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = \
+ gstgdkpixbuf.h \
+ gstgdkpixbufsink.h \
+ pixbufscale.h \
+ gstgdkanimation.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/gdk_pixbuf/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/gdk_pixbuf/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstgdkpixbuf.la: $(libgstgdkpixbuf_la_OBJECTS) $(libgstgdkpixbuf_la_DEPENDENCIES) $(EXTRA_libgstgdkpixbuf_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstgdkpixbuf_la_LINK) -rpath $(plugindir) $(libgstgdkpixbuf_la_OBJECTS) $(libgstgdkpixbuf_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstgdkpixbuf_la-gstgdkpixbuf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstgdkpixbuf_la-gstgdkpixbufsink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstgdkpixbuf_la-pixbufscale.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstgdkpixbuf_la-gstgdkpixbuf.lo: gstgdkpixbuf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgdkpixbuf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgdkpixbuf_la_CFLAGS) $(CFLAGS) -MT libgstgdkpixbuf_la-gstgdkpixbuf.lo -MD -MP -MF $(DEPDIR)/libgstgdkpixbuf_la-gstgdkpixbuf.Tpo -c -o libgstgdkpixbuf_la-gstgdkpixbuf.lo `test -f 'gstgdkpixbuf.c' || echo '$(srcdir)/'`gstgdkpixbuf.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstgdkpixbuf_la-gstgdkpixbuf.Tpo $(DEPDIR)/libgstgdkpixbuf_la-gstgdkpixbuf.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstgdkpixbuf.c' object='libgstgdkpixbuf_la-gstgdkpixbuf.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgdkpixbuf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgdkpixbuf_la_CFLAGS) $(CFLAGS) -c -o libgstgdkpixbuf_la-gstgdkpixbuf.lo `test -f 'gstgdkpixbuf.c' || echo '$(srcdir)/'`gstgdkpixbuf.c
+
+libgstgdkpixbuf_la-gstgdkpixbufsink.lo: gstgdkpixbufsink.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgdkpixbuf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgdkpixbuf_la_CFLAGS) $(CFLAGS) -MT libgstgdkpixbuf_la-gstgdkpixbufsink.lo -MD -MP -MF $(DEPDIR)/libgstgdkpixbuf_la-gstgdkpixbufsink.Tpo -c -o libgstgdkpixbuf_la-gstgdkpixbufsink.lo `test -f 'gstgdkpixbufsink.c' || echo '$(srcdir)/'`gstgdkpixbufsink.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstgdkpixbuf_la-gstgdkpixbufsink.Tpo $(DEPDIR)/libgstgdkpixbuf_la-gstgdkpixbufsink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstgdkpixbufsink.c' object='libgstgdkpixbuf_la-gstgdkpixbufsink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgdkpixbuf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgdkpixbuf_la_CFLAGS) $(CFLAGS) -c -o libgstgdkpixbuf_la-gstgdkpixbufsink.lo `test -f 'gstgdkpixbufsink.c' || echo '$(srcdir)/'`gstgdkpixbufsink.c
+
+libgstgdkpixbuf_la-pixbufscale.lo: pixbufscale.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgdkpixbuf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgdkpixbuf_la_CFLAGS) $(CFLAGS) -MT libgstgdkpixbuf_la-pixbufscale.lo -MD -MP -MF $(DEPDIR)/libgstgdkpixbuf_la-pixbufscale.Tpo -c -o libgstgdkpixbuf_la-pixbufscale.lo `test -f 'pixbufscale.c' || echo '$(srcdir)/'`pixbufscale.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstgdkpixbuf_la-pixbufscale.Tpo $(DEPDIR)/libgstgdkpixbuf_la-pixbufscale.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pixbufscale.c' object='libgstgdkpixbuf_la-pixbufscale.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstgdkpixbuf_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstgdkpixbuf_la_CFLAGS) $(CFLAGS) -c -o libgstgdkpixbuf_la-pixbufscale.lo `test -f 'pixbufscale.c' || echo '$(srcdir)/'`pixbufscale.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/gdk_pixbuf/gstgdkanimation.h b/ext/gdk_pixbuf/gstgdkanimation.h
new file mode 100644
index 0000000..b6b2529
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkanimation.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_LOADER_H__
+#define __GST_LOADER_H__
+
+#include <gst/gst.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk-pixbuf/gdk-pixbuf-animation.h>
+#include <gdk-pixbuf/gdk-pixbuf-io.h>
+#include <stdio.h>
+
+G_BEGIN_DECLS
+
+/* how many bytes we need to have available before we dare to start a new iteration */
+#define GST_GDK_BUFFER_SIZE (102400)
+/* how far behind we need to be before we attempt to seek */
+#define GST_GDK_MAX_DELAY_TO_SEEK (GST_SECOND / 4)
+
+
+#define GST_TYPE_GDK_ANIMATION (gst_gdk_animation_get_type())
+#define GST_GDK_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_ANIMATION,GstGdkAnimation))
+#define GST_GDK_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_ANIMATION,GstGdkAnimationClass))
+#define GST_IS_GDK_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_ANIMATION))
+#define GST_IS_GDK_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_ANIMATION))
+
+typedef struct _GstGdkAnimation GstGdkAnimation;
+typedef struct _GstGdkAnimationClass GstGdkAnimationClass;
+
+typedef struct _GstGdkAnimationIter GstGdkAnimationIter;
+typedef struct _GstGdkAnimationIterClass GstGdkAnimationIterClass;
+
+struct _GstGdkAnimation
+{
+ GdkPixbufAnimation parent;
+
+ /* name of temporary buffer file */
+ gchar * temp_location;
+ /* file descriptor to temporary file or 0 if we're done writing */
+ int temp_fd;
+
+ /* size of image */
+ gint width;
+ gint height;
+ gint bpp;
+ /* static image we use */
+ GdkPixbuf * pixbuf;
+};
+
+struct _GstGdkAnimationClass
+{
+ GdkPixbufAnimationClass parent_class;
+};
+
+GType gst_gdk_animation_get_type (void);
+
+GstGdkAnimation * gst_gdk_animation_new (GError **error);
+
+gboolean gst_gdk_animation_add_data (GstGdkAnimation * ani,
+ const guint8 * data,
+ guint size);
+void gst_gdk_animation_done_adding (GstGdkAnimation * ani);
+
+
+#define GST_TYPE_GDK_ANIMATION_ITER (gst_gdk_animation_iter_get_type ())
+#define GST_GDK_ANIMATION_ITER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GST_TYPE_GDK_ANIMATION_ITER, GstGdkAnimationIter))
+#define GST_IS_GDK_ANIMATION_ITER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GST_TYPE_GDK_ANIMATION_ITER))
+
+#define GST_GDK_ANIMATION_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GDK_ANIMATION_ITER, GstGdkAnimationIterClass))
+#define GST_IS_GDK_ANIMATION_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GDK_ANIMATION_ITER))
+#define GST_GDK_ANIMATION_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_GDK_ANIMATION_ITER, GstGdkAnimationIterClass))
+
+struct _GstGdkAnimationIter {
+ GdkPixbufAnimationIter parent;
+
+ /* our animation */
+ GstGdkAnimation * ani;
+ /* start timeval */
+ GTimeVal start;
+ /* timestamp of last buffer */
+ GstClockTime last_timestamp;
+
+ /* pipeline we're using */
+ GstElement * pipeline;
+ gboolean eos;
+ gboolean just_seeked;
+
+ /* current image and the buffers containing the data */
+ GdkPixbuf * pixbuf;
+ GQueue * buffers;
+};
+
+struct _GstGdkAnimationIterClass {
+ GdkPixbufAnimationIterClass parent_class;
+};
+
+GType gst_gdk_animation_iter_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GST_GDK_ANIMATION_H__ */
diff --git a/ext/gdk_pixbuf/gstgdkpixbuf.c b/ext/gdk_pixbuf/gstgdkpixbuf.c
new file mode 100644
index 0000000..0a09400
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkpixbuf.c
@@ -0,0 +1,558 @@
+/* GStreamer GdkPixbuf-based image decoder
+ * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2003 David A. Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <string.h>
+
+#include "gstgdkpixbuf.h"
+#include "gstgdkpixbufsink.h"
+#include "pixbufscale.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_gdk_pixbuf_debug);
+#define GST_CAT_DEFAULT gst_gdk_pixbuf_debug
+
+enum
+{
+ ARG_0,
+ ARG_SILENT /* FIXME 0.11: remove */
+};
+
+static GstStaticPadTemplate gst_gdk_pixbuf_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("image/png; "
+ /* "image/jpeg; " disabled because we can't handle MJPEG */
+ "image/gif; "
+ "image/x-icon; "
+ "application/x-navi-animation; "
+ "image/x-cmu-raster; "
+ "image/x-sun-raster; "
+ "image/x-pixmap; "
+ "image/tiff; "
+ "image/x-portable-anymap; "
+ "image/x-portable-bitmap; "
+ "image/x-portable-graymap; "
+ "image/x-portable-pixmap; "
+ "image/bmp; "
+ "image/x-bmp; "
+ "image/x-MS-bmp; "
+ "image/vnd.wap.wbmp; " "image/x-bitmap; " "image/x-tga; "
+ "image/x-pcx; image/svg; image/svg+xml")
+ );
+
+static GstStaticPadTemplate gst_gdk_pixbuf_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB "; " GST_VIDEO_CAPS_RGBA)
+ );
+
+static void gst_gdk_pixbuf_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_gdk_pixbuf_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn
+gst_gdk_pixbuf_change_state (GstElement * element, GstStateChange transition);
+static GstFlowReturn gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_gdk_pixbuf_sink_event (GstPad * pad, GstEvent * event);
+
+#ifdef enable_typefind
+static void gst_gdk_pixbuf_type_find (GstTypeFind * tf, gpointer ignore);
+#endif
+
+GST_BOILERPLATE (GstGdkPixbuf, gst_gdk_pixbuf, GstElement, GST_TYPE_ELEMENT);
+
+static gboolean
+gst_gdk_pixbuf_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstGdkPixbuf *filter;
+ const GValue *framerate;
+ GstStructure *s;
+
+ filter = GST_GDK_PIXBUF (GST_PAD_PARENT (pad));
+ s = gst_caps_get_structure (caps, 0);
+
+ if ((framerate = gst_structure_get_value (s, "framerate")) != NULL) {
+ filter->framerate_numerator = gst_value_get_fraction_numerator (framerate);
+ filter->framerate_denominator =
+ gst_value_get_fraction_denominator (framerate);
+ GST_DEBUG_OBJECT (filter, "got framerate of %d/%d fps => packetized mode",
+ filter->framerate_numerator, filter->framerate_denominator);
+ } else {
+ filter->framerate_numerator = 0;
+ filter->framerate_denominator = 1;
+ GST_DEBUG_OBJECT (filter, "no framerate, assuming single image");
+ }
+
+ return TRUE;
+}
+
+static GstCaps *
+gst_gdk_pixbuf_get_capslist (void)
+{
+ GSList *slist;
+ GSList *slist0;
+ GstCaps *capslist = NULL;
+ GstCaps *return_caps = NULL;
+ GstCaps *tmpl_caps;
+
+ capslist = gst_caps_new_empty ();
+ slist0 = gdk_pixbuf_get_formats ();
+
+ for (slist = slist0; slist; slist = g_slist_next (slist)) {
+ GdkPixbufFormat *pixbuf_format;
+ char **mimetypes;
+ char **mimetype;
+
+ pixbuf_format = slist->data;
+ mimetypes = gdk_pixbuf_format_get_mime_types (pixbuf_format);
+
+ for (mimetype = mimetypes; *mimetype; mimetype++) {
+ gst_caps_append_structure (capslist, gst_structure_new (*mimetype, NULL));
+ }
+ g_strfreev (mimetypes);
+ }
+ g_slist_free (slist0);
+
+ tmpl_caps = gst_static_caps_get (&gst_gdk_pixbuf_sink_template.static_caps);
+ return_caps = gst_caps_intersect (capslist, tmpl_caps);
+
+ gst_caps_unref (tmpl_caps);
+ gst_caps_unref (capslist);
+ return return_caps;
+}
+
+static GstCaps *
+gst_gdk_pixbuf_sink_getcaps (GstPad * pad)
+{
+ return gst_gdk_pixbuf_get_capslist ();
+}
+
+static void
+gst_gdk_pixbuf_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_gdk_pixbuf_src_template);
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_gdk_pixbuf_sink_template);
+ gst_element_class_set_details_simple (element_class,
+ "GdkPixbuf image decoder", "Codec/Decoder/Image",
+ "Decodes images in a video stream using GdkPixbuf",
+ "David A. Schleef <ds@schleef.org>, Renato Filho <renato.filho@indt.org.br>");
+}
+
+/* initialize the plugin's class */
+static void
+gst_gdk_pixbuf_class_init (GstGdkPixbufClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->set_property = gst_gdk_pixbuf_set_property;
+ gobject_class->get_property = gst_gdk_pixbuf_get_property;
+
+ g_object_class_install_property (gobject_class, ARG_SILENT,
+ g_param_spec_boolean ("silent", "Silent",
+ "Produce verbose output ? (deprecated)", FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_change_state);
+}
+
+static void
+gst_gdk_pixbuf_init (GstGdkPixbuf * filter, GstGdkPixbufClass * klass)
+{
+ filter->sinkpad =
+ gst_pad_new_from_static_template (&gst_gdk_pixbuf_sink_template, "sink");
+ gst_pad_set_setcaps_function (filter->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_setcaps));
+ gst_pad_set_getcaps_function (filter->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_getcaps));
+ gst_pad_set_chain_function (filter->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_chain));
+ gst_pad_set_event_function (filter->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_event));
+ gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
+
+ filter->srcpad =
+ gst_pad_new_from_static_template (&gst_gdk_pixbuf_src_template, "src");
+ gst_pad_use_fixed_caps (filter->srcpad);
+ gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
+
+ filter->last_timestamp = GST_CLOCK_TIME_NONE;
+ filter->pixbuf_loader = NULL;
+}
+
+static GstFlowReturn
+gst_gdk_pixbuf_flush (GstGdkPixbuf * filter)
+{
+ GstBuffer *outbuf;
+ GdkPixbuf *pixbuf;
+ int y;
+ guint8 *out_pix;
+ guint8 *in_pix;
+ int in_rowstride;
+ GstFlowReturn ret;
+ GstCaps *caps = NULL;
+ gint n_channels;
+
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (filter->pixbuf_loader);
+ if (pixbuf == NULL)
+ goto no_pixbuf;
+
+ if (filter->image_size == 0) {
+ filter->width = gdk_pixbuf_get_width (pixbuf);
+ filter->height = gdk_pixbuf_get_height (pixbuf);
+ filter->rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ filter->image_size = filter->rowstride * filter->height;
+
+ n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+ switch (n_channels) {
+ case 3:
+ caps = gst_caps_from_string (GST_VIDEO_CAPS_RGB);
+ break;
+ case 4:
+ caps = gst_caps_from_string (GST_VIDEO_CAPS_RGBA);
+ break;
+ default:
+ goto channels_not_supported;
+ }
+
+ gst_caps_set_simple (caps,
+ "width", G_TYPE_INT, filter->width,
+ "height", G_TYPE_INT, filter->height,
+ "framerate", GST_TYPE_FRACTION, filter->framerate_numerator,
+ filter->framerate_denominator, NULL);
+
+ GST_DEBUG ("Set size to %dx%d", filter->width, filter->height);
+ gst_pad_set_caps (filter->srcpad, caps);
+ gst_caps_unref (caps);
+ }
+
+ ret = gst_pad_alloc_buffer_and_set_caps (filter->srcpad,
+ GST_BUFFER_OFFSET_NONE,
+ filter->image_size, GST_PAD_CAPS (filter->srcpad), &outbuf);
+
+ if (ret != GST_FLOW_OK)
+ goto no_buffer;
+
+ GST_BUFFER_TIMESTAMP (outbuf) = filter->last_timestamp;
+ GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
+
+ in_pix = gdk_pixbuf_get_pixels (pixbuf);
+ in_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ out_pix = GST_BUFFER_DATA (outbuf);
+
+ /* FIXME, last line might not have rowstride pixels */
+ for (y = 0; y < filter->height; y++) {
+ memcpy (out_pix, in_pix, filter->rowstride);
+ in_pix += in_rowstride;
+ out_pix += filter->rowstride;
+ }
+
+ GST_DEBUG ("pushing... %d bytes", GST_BUFFER_SIZE (outbuf));
+ ret = gst_pad_push (filter->srcpad, outbuf);
+
+ if (ret != GST_FLOW_OK)
+ GST_DEBUG_OBJECT (filter, "flow: %s", gst_flow_get_name (ret));
+
+ return ret;
+
+ /* ERRORS */
+no_pixbuf:
+ {
+ GST_ELEMENT_ERROR (filter, STREAM, DECODE, (NULL), ("error geting pixbuf"));
+ return GST_FLOW_ERROR;
+ }
+channels_not_supported:
+ {
+ GST_ELEMENT_ERROR (filter, STREAM, DECODE, (NULL),
+ ("%d channels not supported", n_channels));
+ return GST_FLOW_ERROR;
+ }
+no_buffer:
+ {
+ GST_DEBUG ("Failed to create outbuffer - %s", gst_flow_get_name (ret));
+ return ret;
+ }
+}
+
+static gboolean
+gst_gdk_pixbuf_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstFlowReturn res = GST_FLOW_OK;
+ gboolean ret = TRUE;
+ GstGdkPixbuf *pixbuf;
+
+ pixbuf = GST_GDK_PIXBUF (gst_pad_get_parent (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ if (pixbuf->pixbuf_loader != NULL) {
+ gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL);
+ res = gst_gdk_pixbuf_flush (pixbuf);
+ g_object_unref (G_OBJECT (pixbuf->pixbuf_loader));
+ pixbuf->pixbuf_loader = NULL;
+ /* as long as we don't have flow returns for event functions we need
+ * to post an error here, or the application might never know that
+ * things failed */
+ if (res != GST_FLOW_OK && res != GST_FLOW_WRONG_STATE) {
+ GST_ELEMENT_ERROR (pixbuf, STREAM, FAILED, (NULL),
+ ("Flow: %s", gst_flow_get_name (res)));
+ }
+ }
+ break;
+ case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_FLUSH_STOP:
+ if (pixbuf->pixbuf_loader != NULL) {
+ gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL);
+ g_object_unref (G_OBJECT (pixbuf->pixbuf_loader));
+ pixbuf->pixbuf_loader = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (res == GST_FLOW_OK) {
+ ret = gst_pad_event_default (pad, event);
+ } else {
+ ret = FALSE;
+ }
+
+ gst_object_unref (pixbuf);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstGdkPixbuf *filter;
+ GstFlowReturn ret = GST_FLOW_OK;
+ GError *error = NULL;
+ GstClockTime timestamp;
+ guint8 *data;
+ guint size;
+
+ filter = GST_GDK_PIXBUF (gst_pad_get_parent (pad));
+
+ timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ if (GST_CLOCK_TIME_IS_VALID (timestamp))
+ filter->last_timestamp = timestamp;
+
+ GST_LOG_OBJECT (filter, "buffer with ts: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp));
+
+ if (filter->pixbuf_loader == NULL)
+ filter->pixbuf_loader = gdk_pixbuf_loader_new ();
+
+ data = GST_BUFFER_DATA (buf);
+ size = GST_BUFFER_SIZE (buf);
+
+ GST_LOG_OBJECT (filter, "Writing buffer size %d", size);
+ if (!gdk_pixbuf_loader_write (filter->pixbuf_loader, data, size, &error))
+ goto error;
+
+ /* packetised mode? */
+ if (filter->framerate_numerator != 0) {
+ gdk_pixbuf_loader_close (filter->pixbuf_loader, NULL);
+ ret = gst_gdk_pixbuf_flush (filter);
+ g_object_unref (filter->pixbuf_loader);
+ filter->pixbuf_loader = NULL;
+ }
+
+ gst_buffer_unref (buf);
+ gst_object_unref (filter);
+
+ return ret;
+
+ /* ERRORS */
+error:
+ {
+ GST_ELEMENT_ERROR (filter, STREAM, DECODE, (NULL),
+ ("gdk_pixbuf_loader_write error: %s", error->message));
+ g_error_free (error);
+ gst_buffer_unref (buf);
+ gst_object_unref (filter);
+ return GST_FLOW_ERROR;
+ }
+}
+
+static void
+gst_gdk_pixbuf_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ switch (prop_id) {
+ case ARG_SILENT:
+ /* filter->silent = g_value_get_boolean (value); */
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_gdk_pixbuf_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ 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;
+ }
+}
+
+static GstStateChangeReturn
+gst_gdk_pixbuf_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstGdkPixbuf *dec = GST_GDK_PIXBUF (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ /* default to single image mode, setcaps function might not be called */
+ dec->framerate_numerator = 0;
+ dec->framerate_denominator = 1;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ dec->framerate_numerator = 0;
+ dec->framerate_denominator = 0;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+#define GST_GDK_PIXBUF_TYPE_FIND_SIZE 1024
+
+#ifdef enable_typefind
+static void
+gst_gdk_pixbuf_type_find (GstTypeFind * tf, gpointer ignore)
+{
+ guint8 *data;
+ GdkPixbufLoader *pixbuf_loader;
+ GdkPixbufFormat *format;
+
+ data = gst_type_find_peek (tf, 0, GST_GDK_PIXBUF_TYPE_FIND_SIZE);
+ if (data == NULL)
+ return;
+
+ GST_DEBUG ("creating new loader");
+
+ pixbuf_loader = gdk_pixbuf_loader_new ();
+
+ gdk_pixbuf_loader_write (pixbuf_loader, data, GST_GDK_PIXBUF_TYPE_FIND_SIZE,
+ NULL);
+
+ format = gdk_pixbuf_loader_get_format (pixbuf_loader);
+
+ if (format != NULL) {
+ GstCaps *caps;
+ gchar **p;
+ gchar **mlist = gdk_pixbuf_format_get_mime_types (format);
+
+ for (p = mlist; *p; ++p) {
+ GST_DEBUG ("suggesting mime type %s", *p);
+ caps = gst_caps_new_simple (*p, NULL);
+ gst_type_find_suggest (tf, GST_TYPE_FIND_MINIMUM, caps);
+ gst_caps_free (caps);
+ }
+ g_strfreev (mlist);
+ }
+
+ GST_DEBUG ("closing pixbuf loader, hope it doesn't hang ...");
+ /* librsvg 2.4.x has a bug where it triggers an endless loop in trying
+ to close a gzip that's not an svg; fixed upstream but no good way
+ to work around it */
+ gdk_pixbuf_loader_close (pixbuf_loader, NULL);
+ GST_DEBUG ("closed pixbuf loader");
+ g_object_unref (G_OBJECT (pixbuf_loader));
+}
+#endif
+
+/* entry point to initialize the plug-in
+ * initialize the plug-in itself
+ * register the element factories and pad templates
+ * register the features
+ */
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (gst_gdk_pixbuf_debug, "gdkpixbuf", 0,
+ "gdk pixbuf loader");
+
+ if (!gst_element_register (plugin, "gdkpixbufdec", GST_RANK_SECONDARY,
+ GST_TYPE_GDK_PIXBUF))
+ return FALSE;
+
+#ifdef enable_typefind
+ gst_type_find_register (plugin, "image/*", GST_RANK_MARGINAL,
+ gst_gdk_pixbuf_type_find, NULL, GST_CAPS_ANY, NULL);
+#endif
+
+ if (!gst_element_register (plugin, "gdkpixbufsink", GST_RANK_NONE,
+ GST_TYPE_GDK_PIXBUF_SINK))
+ return FALSE;
+
+ if (!pixbufscale_init (plugin))
+ return FALSE;
+
+ /* plugin initialisation succeeded */
+ return TRUE;
+}
+
+
+/* this is the structure that gst-register looks for
+ * so keep the name plugin_desc, or you cannot get your plug-in registered */
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "gdkpixbuf",
+ "GdkPixbuf-based image decoder, scaler and sink",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/gdk_pixbuf/gstgdkpixbuf.h b/ext/gdk_pixbuf/gstgdkpixbuf.h
new file mode 100644
index 0000000..a4c6ee5
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkpixbuf.h
@@ -0,0 +1,70 @@
+/* GStreamer GdkPixbuf-based image decoder
+ * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2003 David A. Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_GDK_PIXBUF_H__
+#define __GST_GDK_PIXBUF_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+/* #define's don't like whitespacey bits */
+#define GST_TYPE_GDK_PIXBUF \
+ (gst_gdk_pixbuf_get_type())
+#define GST_GDK_PIXBUF(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_PIXBUF,GstGdkPixbuf))
+#define GST_GDK_PIXBUF_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_PIXBUF,GstGdkPixbufClass))
+#define GST_IS_GDK_PIXBUF(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_PIXBUF))
+#define GST_IS_GDK_PIXBUF_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_PIXBUF))
+
+typedef struct _GstGdkPixbuf GstGdkPixbuf;
+typedef struct _GstGdkPixbufClass GstGdkPixbufClass;
+
+struct _GstGdkPixbuf
+{
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+
+ GstClockTime last_timestamp;
+ GdkPixbufLoader *pixbuf_loader;
+
+ int width;
+ int height;
+ int rowstride;
+ unsigned int image_size;
+
+ gint framerate_numerator;
+ gint framerate_denominator;
+};
+
+struct _GstGdkPixbufClass
+{
+ GstElementClass parent_class;
+};
+
+static GType gst_gdk_pixbuf_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_GDK_PIXBUF_H__ */
diff --git a/ext/gdk_pixbuf/gstgdkpixbufsink.c b/ext/gdk_pixbuf/gstgdkpixbufsink.c
new file mode 100644
index 0000000..2c2714e
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkpixbufsink.c
@@ -0,0 +1,426 @@
+/* GStreamer GdkPixbuf sink
+ * Copyright (C) 2006-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is free software; you can redistribute it and/or
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-gdkpixbufsink
+ * @Since: 0.10.8
+ *
+ * This sink element takes RGB or RGBA images as input and wraps them into
+ * #GdkPixbuf objects, for easy saving to file via the
+ * GdkPixbuf library API or displaying in Gtk+ applications (e.g. using
+ * the #GtkImage widget).
+ *
+ * There are two ways to use this element and obtain the #GdkPixbuf objects
+ * created:
+ * <itemizedlist>
+ * <listitem>
+ * Watching for element messages named <classname>&quot;preroll-pixbuf&quot;
+ * </classname> or <classname>&quot;pixbuf&quot;</classname> on the bus, which
+ * will be posted whenever an image would usually be rendered. See below for
+ * more details on these messages and how to extract the pixbuf object
+ * contained in them.
+ * </listitem>
+ * <listitem>
+ * Retrieving the current pixbuf via the #GstGdkPixbufSink:last-pixbuf property
+ * when needed.
+ * </listitem>
+ * </itemizedlist>
+ *
+ * The primary purpose of this element is to abstract away the #GstBuffer to
+ * #GdkPixbuf conversion. Other than that it's very similar to the fakesink
+ * element.
+ *
+ * This element is meant for easy no-hassle video snapshotting. It is not
+ * suitable for video playback or video display at high framerates. Use
+ * ximagesink, xvimagesink or some other suitable video sink in connection
+ * with the #GstXOverlay interface instead if you want to do video playback.
+ *
+ * <refsect2>
+ * <title>Message details</title>
+ * As mentioned above, this element will by default post element messages
+ * containing structures named <classname>&quot;preroll-pixbuf&quot;
+ * </classname> or <classname>&quot;pixbuf&quot;</classname> on the bus (this
+ * can be disabled by setting the #GstGdkPixbufSink:post-messages property
+ * to #FALSE though). The element message structure has the following fields:
+ * <itemizedlist>
+ * <listitem>
+ * <classname>&quot;pixbuf&quot;</classname>: the #GdkPixbuf object
+ * </listitem>
+ * <listitem>
+ * <classname>&quot;pixel-aspect-ratio&quot;</classname>: the pixel aspect
+ * ratio (PAR) of the input image (this field contains a #GstFraction); the
+ * PAR is usually 1:1 for images, but is often something non-1:1 in the case
+ * of video input. In this case the image may be distorted and you may need
+ * to rescale it accordingly before saving it to file or displaying it. This
+ * can easily be done using gdk_pixbuf_scale() (the reason this is not done
+ * automatically is that the application will often scale the image anyway
+ * according to the size of the output window, in which case it is much more
+ * efficient to only scale once rather than twice). You can put a videoscale
+ * element and a capsfilter element with
+ * <literal>video/x-raw-rgb,pixel-aspect-ratio=(fraction)1/1</literal> caps
+ * in front of this element to make sure the pixbufs always have a 1:1 PAR.
+ * </listitem>
+ * </itemizedlist>
+ * </refsect2>
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch -m -v videotestsrc num-buffers=1 ! gdkpixbufsink
+ * ]| Process one single test image as pixbuf (note that the output you see will
+ * be slightly misleading. The message structure does contain a valid pixbuf
+ * object even if the structure string says &apos;(NULL)&apos;).
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstgdkpixbufsink.h"
+
+#include <gst/video/video.h>
+
+#define DEFAULT_SEND_MESSAGES TRUE
+#define DEFAULT_POST_MESSAGES TRUE
+
+enum
+{
+ PROP_0,
+ PROP_SEND_MESSAGES,
+ PROP_POST_MESSAGES,
+ PROP_LAST_PIXBUF,
+ PROP_LAST
+};
+
+
+GST_BOILERPLATE (GstGdkPixbufSink, gst_gdk_pixbuf_sink, GstVideoSink,
+ GST_TYPE_VIDEO_SINK);
+
+static void gst_gdk_pixbuf_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_gdk_pixbuf_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static gboolean gst_gdk_pixbuf_sink_start (GstBaseSink * basesink);
+static gboolean gst_gdk_pixbuf_sink_stop (GstBaseSink * basesink);
+static gboolean gst_gdk_pixbuf_sink_set_caps (GstBaseSink * basesink,
+ GstCaps * caps);
+static GstFlowReturn gst_gdk_pixbuf_sink_render (GstBaseSink * bsink,
+ GstBuffer * buf);
+static GstFlowReturn gst_gdk_pixbuf_sink_preroll (GstBaseSink * bsink,
+ GstBuffer * buf);
+static GdkPixbuf *gst_gdk_pixbuf_sink_get_pixbuf_from_buffer (GstGdkPixbufSink *
+ sink, GstBuffer * buf);
+
+#define WxH ", width = (int) [ 16, 4096 ], height = (int) [ 16, 4096 ]"
+
+static GstStaticPadTemplate pixbufsink_sink_factory =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB WxH ";" GST_VIDEO_CAPS_RGBA WxH));
+
+static void
+gst_gdk_pixbuf_sink_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details_simple (element_class, "GdkPixbuf sink",
+ "Sink/Video", "Output images as GdkPixbuf objects in bus messages",
+ "Tim-Philipp Müller <tim centricular net>");
+
+ gst_element_class_add_static_pad_template (element_class,
+ &pixbufsink_sink_factory);
+}
+
+static void
+gst_gdk_pixbuf_sink_class_init (GstGdkPixbufSinkClass * klass)
+{
+ GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = gst_gdk_pixbuf_sink_set_property;
+ gobject_class->get_property = gst_gdk_pixbuf_sink_get_property;
+
+ /* FIXME 0.11, remove in favour of post-messages */
+ g_object_class_install_property (gobject_class, PROP_SEND_MESSAGES,
+ g_param_spec_boolean ("send-messages", "Send Messages",
+ "Whether to post messages containing pixbufs on the bus "
+ " (deprecated, use post-messages)",
+ DEFAULT_SEND_MESSAGES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstGdkPixbuf:post-messages:
+ *
+ * Post messages on the bus containing pixbufs.
+ *
+ * Since: 0.10.17
+ */
+ g_object_class_install_property (gobject_class, PROP_POST_MESSAGES,
+ g_param_spec_boolean ("post-messages", "Post Messages",
+ "Whether to post messages containing pixbufs on the bus",
+ DEFAULT_POST_MESSAGES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_LAST_PIXBUF,
+ g_param_spec_object ("last-pixbuf", "Last Pixbuf",
+ "Last GdkPixbuf object rendered", GDK_TYPE_PIXBUF,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ basesink_class->start = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_start);
+ basesink_class->stop = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_stop);
+ basesink_class->render = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_render);
+ basesink_class->preroll = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_preroll);
+ basesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_set_caps);
+}
+
+static void
+gst_gdk_pixbuf_sink_init (GstGdkPixbufSink * sink,
+ GstGdkPixbufSinkClass * klass)
+{
+ sink->par_n = 0;
+ sink->par_d = 0;
+ sink->has_alpha = FALSE;
+ sink->last_pixbuf = NULL;
+ sink->post_messages = DEFAULT_POST_MESSAGES;
+
+ /* we're not a real video sink, we just derive from GstVideoSink in case
+ * anything interesting is added to it in future */
+ gst_base_sink_set_max_lateness (GST_BASE_SINK (sink), -1);
+ gst_base_sink_set_qos_enabled (GST_BASE_SINK (sink), FALSE);
+}
+
+
+static gboolean
+gst_gdk_pixbuf_sink_start (GstBaseSink * basesink)
+{
+ GST_LOG_OBJECT (basesink, "start");
+
+ return TRUE;
+}
+
+static gboolean
+gst_gdk_pixbuf_sink_stop (GstBaseSink * basesink)
+{
+ GstGdkPixbufSink *sink = GST_GDK_PIXBUF_SINK (basesink);
+
+ GST_VIDEO_SINK_WIDTH (sink) = 0;
+ GST_VIDEO_SINK_HEIGHT (sink) = 0;
+
+ sink->par_n = 0;
+ sink->par_d = 0;
+ sink->has_alpha = FALSE;
+
+ if (sink->last_pixbuf) {
+ g_object_unref (sink->last_pixbuf);
+ sink->last_pixbuf = NULL;
+ }
+
+ GST_LOG_OBJECT (sink, "stop");
+
+ return TRUE;
+}
+
+static gboolean
+gst_gdk_pixbuf_sink_set_caps (GstBaseSink * basesink, GstCaps * caps)
+{
+ GstGdkPixbufSink *sink = GST_GDK_PIXBUF_SINK (basesink);
+ GstVideoFormat fmt;
+ gint w, h, par_n, par_d;
+
+ GST_LOG_OBJECT (sink, "caps: %" GST_PTR_FORMAT, caps);
+
+ if (!gst_video_format_parse_caps (caps, &fmt, &w, &h)) {
+ GST_WARNING_OBJECT (sink, "parse_caps failed");
+ return FALSE;
+ }
+
+ if (!gst_video_parse_caps_pixel_aspect_ratio (caps, &par_n, &par_d)) {
+ GST_LOG_OBJECT (sink, "no pixel aspect ratio");
+ return FALSE;
+ }
+
+ g_assert ((fmt == GST_VIDEO_FORMAT_RGB &&
+ gst_video_format_get_pixel_stride (fmt, 0) == 3) ||
+ (fmt == GST_VIDEO_FORMAT_RGBA &&
+ gst_video_format_get_pixel_stride (fmt, 0) == 4));
+
+ GST_VIDEO_SINK_WIDTH (sink) = w;
+ GST_VIDEO_SINK_HEIGHT (sink) = h;
+
+ sink->rowstride = gst_video_format_get_row_stride (fmt, 0, w);
+ sink->has_alpha = (fmt == GST_VIDEO_FORMAT_RGBA);
+
+ sink->par_n = par_n;
+ sink->par_d = par_d;
+
+ GST_INFO_OBJECT (sink, "format : %d", fmt);
+ GST_INFO_OBJECT (sink, "width x height : %d x %d", w, h);
+ GST_INFO_OBJECT (sink, "pixel-aspect-ratio : %d/%d", par_n, par_d);
+
+ return TRUE;
+}
+
+static void
+gst_gdk_pixbuf_sink_pixbuf_destroy_notify (guchar * pixels, GstBuffer * buf)
+{
+ gst_buffer_unref (buf);
+}
+
+static GdkPixbuf *
+gst_gdk_pixbuf_sink_get_pixbuf_from_buffer (GstGdkPixbufSink * sink,
+ GstBuffer * buf)
+{
+ GdkPixbuf *pix = NULL;
+ gint minsize, bytes_per_pixel;
+
+ g_return_val_if_fail (GST_VIDEO_SINK_WIDTH (sink) > 0, NULL);
+ g_return_val_if_fail (GST_VIDEO_SINK_HEIGHT (sink) > 0, NULL);
+
+ bytes_per_pixel = (sink->has_alpha) ? 4 : 3;
+
+ /* last row needn't have row padding */
+ minsize = (sink->rowstride * (GST_VIDEO_SINK_HEIGHT (sink) - 1)) +
+ (bytes_per_pixel * GST_VIDEO_SINK_WIDTH (sink));
+
+ g_return_val_if_fail (GST_BUFFER_SIZE (buf) >= minsize, NULL);
+
+ pix = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buf),
+ GDK_COLORSPACE_RGB, sink->has_alpha, 8, GST_VIDEO_SINK_WIDTH (sink),
+ GST_VIDEO_SINK_HEIGHT (sink), sink->rowstride,
+ (GdkPixbufDestroyNotify) gst_gdk_pixbuf_sink_pixbuf_destroy_notify,
+ gst_buffer_ref (buf));
+
+ return pix;
+}
+
+static GstFlowReturn
+gst_gdk_pixbuf_sink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf,
+ const gchar * msg_name)
+{
+ GstGdkPixbufSink *sink;
+ GdkPixbuf *pixbuf;
+ gboolean do_post;
+
+ sink = GST_GDK_PIXBUF_SINK (basesink);
+
+ pixbuf = gst_gdk_pixbuf_sink_get_pixbuf_from_buffer (sink, buf);
+
+ GST_OBJECT_LOCK (sink);
+
+ do_post = sink->post_messages;
+
+ if (sink->last_pixbuf)
+ g_object_unref (sink->last_pixbuf);
+
+ sink->last_pixbuf = pixbuf; /* take ownership */
+
+ GST_OBJECT_UNLOCK (sink);
+
+ if (G_UNLIKELY (pixbuf == NULL))
+ goto error;
+
+ if (do_post) {
+ GstStructure *s;
+ GstMessage *msg;
+
+ /* it's okay to keep using pixbuf here, we can be sure no one is going to
+ * unref or change sink->last_pixbuf before we return from this function.
+ * The structure will take its own ref to the pixbuf. */
+ s = gst_structure_new (msg_name,
+ "pixbuf", GDK_TYPE_PIXBUF, pixbuf,
+ "pixel-aspect-ratio", GST_TYPE_FRACTION, sink->par_n, sink->par_d,
+ NULL);
+
+ msg = gst_message_new_element (GST_OBJECT_CAST (sink), s);
+ gst_element_post_message (GST_ELEMENT_CAST (sink), msg);
+ }
+
+ g_object_notify (G_OBJECT (sink), "last-pixbuf");
+
+ return GST_FLOW_OK;
+
+/* ERRORS */
+error:
+ {
+ /* This shouldn't really happen */
+ GST_ELEMENT_ERROR (sink, LIBRARY, FAILED,
+ ("Couldn't create pixbuf from RGB image."),
+ ("Probably not enough free memory"));
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstFlowReturn
+gst_gdk_pixbuf_sink_preroll (GstBaseSink * basesink, GstBuffer * buf)
+{
+ return gst_gdk_pixbuf_sink_handle_buffer (basesink, buf, "preroll-pixbuf");
+}
+
+static GstFlowReturn
+gst_gdk_pixbuf_sink_render (GstBaseSink * basesink, GstBuffer * buf)
+{
+ return gst_gdk_pixbuf_sink_handle_buffer (basesink, buf, "pixbuf");
+}
+
+static void
+gst_gdk_pixbuf_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstGdkPixbufSink *sink;
+
+ sink = GST_GDK_PIXBUF_SINK (object);
+
+ switch (prop_id) {
+ case PROP_SEND_MESSAGES:
+ case PROP_POST_MESSAGES:
+ GST_OBJECT_LOCK (sink);
+ sink->post_messages = g_value_get_boolean (value);
+ GST_OBJECT_UNLOCK (sink);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_gdk_pixbuf_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstGdkPixbufSink *sink;
+
+ sink = GST_GDK_PIXBUF_SINK (object);
+
+ switch (prop_id) {
+ case PROP_SEND_MESSAGES:
+ case PROP_POST_MESSAGES:
+ GST_OBJECT_LOCK (sink);
+ g_value_set_boolean (value, sink->post_messages);
+ GST_OBJECT_UNLOCK (sink);
+ break;
+ case PROP_LAST_PIXBUF:
+ GST_OBJECT_LOCK (sink);
+ g_value_set_object (value, sink->last_pixbuf);
+ GST_OBJECT_UNLOCK (sink);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
diff --git a/ext/gdk_pixbuf/gstgdkpixbufsink.h b/ext/gdk_pixbuf/gstgdkpixbufsink.h
new file mode 100644
index 0000000..b0eff5e
--- /dev/null
+++ b/ext/gdk_pixbuf/gstgdkpixbufsink.h
@@ -0,0 +1,75 @@
+/* GStreamer GdkPixbuf sink
+ * Copyright (C) 2006-2008 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GST_GDK_PIXBUF_SINK_H
+#define GST_GDK_PIXBUF_SINK_H
+
+#include <gst/gst.h>
+
+#include <gst/video/gstvideosink.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define GST_TYPE_GDK_PIXBUF_SINK (gst_gdk_pixbuf_sink_get_type())
+#define GST_GDK_PIXBUF_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_PIXBUF_SINK,GstGdkPixbufSink))
+#define GST_GDK_PIXBUF_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_PIXBUF_SINK,GstGdkPixbufSinkClass))
+#define GST_IS_GDK_PIXBUF_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_PIXBUF_SINK))
+#define GST_IS_GDK_PIXBUF_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_PIXBUF_SINK))
+
+typedef struct _GstGdkPixbufSink GstGdkPixbufSink;
+typedef struct _GstGdkPixbufSinkClass GstGdkPixbufSinkClass;
+
+/**
+ * GstGdkPixbufSink:
+ *
+ * Opaque element structure.
+ */
+struct _GstGdkPixbufSink
+{
+ GstVideoSink basesink;
+
+ /*< private >*/
+
+ /* current caps */
+ gint width;
+ gint height;
+ gint rowstride;
+ gint par_n;
+ gint par_d;
+ gboolean has_alpha;
+
+ /* properties */
+ gboolean post_messages;
+ GdkPixbuf * last_pixbuf;
+};
+
+/**
+ * GstGdkPixbufSinkClass:
+ *
+ * Opaque element class structure.
+ */
+struct _GstGdkPixbufSinkClass
+{
+ GstVideoSinkClass basesinkclass;
+};
+
+GType gst_gdk_pixbuf_sink_get_type (void);
+
+#endif /* GST_GDK_PIXBUF_SINK_H */
+
diff --git a/ext/gdk_pixbuf/pixbufscale.c b/ext/gdk_pixbuf/pixbufscale.c
new file mode 100644
index 0000000..ba98f62
--- /dev/null
+++ b/ext/gdk_pixbuf/pixbufscale.c
@@ -0,0 +1,483 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2004> Jan Schmidt <thaytan@mad.scientist.com>
+ * Copyright (C) <2004> Tim-Philipp Mueller <t.i.m@orange.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <pixbufscale.h>
+#include <gst/video/video.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#define ROUND_UP_2(x) (((x)+1)&~1)
+#define ROUND_UP_4(x) (((x)+3)&~3)
+#define ROUND_UP_8(x) (((x)+7)&~7)
+
+/* These match the ones gstffmpegcolorspace uses (Tim) */
+#define GST_RGB24_ROWSTRIDE(width) (ROUND_UP_4 ((width)*3))
+#define GST_RGB24_SIZE(width,height) ((height)*GST_RGB24_ROWSTRIDE(width))
+
+
+GST_DEBUG_CATEGORY_STATIC (pixbufscale_debug);
+#define GST_CAT_DEFAULT pixbufscale_debug
+
+/* GstPixbufScale signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+ ARG_METHOD
+ /* FILL ME */
+};
+
+static GstStaticPadTemplate gst_pixbufscale_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB)
+ );
+
+static GstStaticPadTemplate gst_pixbufscale_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB)
+ );
+
+#define GST_TYPE_PIXBUFSCALE_METHOD (gst_pixbufscale_method_get_type())
+static GType
+gst_pixbufscale_method_get_type (void)
+{
+ static GType pixbufscale_method_type = 0;
+ static const GEnumValue pixbufscale_methods[] = {
+ {GST_PIXBUFSCALE_NEAREST, "0", "Nearest Neighbour"},
+ {GST_PIXBUFSCALE_TILES, "1", "Tiles"},
+ {GST_PIXBUFSCALE_BILINEAR, "2", "Bilinear"},
+ {GST_PIXBUFSCALE_HYPER, "3", "Hyper"},
+ {0, NULL, NULL},
+ };
+
+ if (!pixbufscale_method_type) {
+ pixbufscale_method_type =
+ g_enum_register_static ("GstPixbufScaleMethod", pixbufscale_methods);
+ }
+ return pixbufscale_method_type;
+}
+
+static void gst_pixbufscale_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_pixbufscale_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_pixbufscale_transform_caps (GstBaseTransform * trans,
+ GstPadDirection direction, GstCaps * caps);
+static gboolean gst_pixbufscale_set_caps (GstBaseTransform * trans,
+ GstCaps * in, GstCaps * out);
+static gboolean gst_pixbufscale_get_unit_size (GstBaseTransform * trans,
+ GstCaps * caps, guint * size);
+static void gst_pixbufscale_fixate_caps (GstBaseTransform * base,
+ GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
+static GstFlowReturn gst_pixbufscale_transform (GstBaseTransform * trans,
+ GstBuffer * in, GstBuffer * out);
+static gboolean gst_pixbufscale_handle_src_event (GstPad * pad,
+ GstEvent * event);
+
+
+static gboolean parse_caps (GstCaps * caps, gint * width, gint * height);
+
+GST_BOILERPLATE (GstPixbufScale, gst_pixbufscale, GstBaseTransform,
+ GST_TYPE_BASE_TRANSFORM);
+
+static void
+gst_pixbufscale_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details_simple (element_class, "GdkPixbuf image scaler",
+ "Filter/Effect/Video", "Resizes video",
+ "Jan Schmidt <thaytan@mad.scientist.com>, "
+ "Wim Taymans <wim.taymans@chello.be>, "
+ "Renato Filho <renato.filho@indt.org.br>");
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_pixbufscale_src_template);
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_pixbufscale_sink_template);
+}
+
+static void
+gst_pixbufscale_class_init (GstPixbufScaleClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstBaseTransformClass *trans_class;
+
+ gobject_class = (GObjectClass *) klass;
+ trans_class = (GstBaseTransformClass *) klass;
+
+ gobject_class->set_property = gst_pixbufscale_set_property;
+ gobject_class->get_property = gst_pixbufscale_get_property;
+
+ g_object_class_install_property (gobject_class,
+ ARG_METHOD,
+ g_param_spec_enum ("method", "method", "method",
+ GST_TYPE_PIXBUFSCALE_METHOD, GST_PIXBUFSCALE_BILINEAR,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ trans_class->transform_caps =
+ GST_DEBUG_FUNCPTR (gst_pixbufscale_transform_caps);
+ trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_pixbufscale_set_caps);
+ trans_class->get_unit_size =
+ GST_DEBUG_FUNCPTR (gst_pixbufscale_get_unit_size);
+ trans_class->transform = GST_DEBUG_FUNCPTR (gst_pixbufscale_transform);
+ trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_pixbufscale_fixate_caps);
+ trans_class->passthrough_on_same_caps = TRUE;
+
+ parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+gst_pixbufscale_init (GstPixbufScale * pixbufscale,
+ GstPixbufScaleClass * kclass)
+{
+ GstBaseTransform *trans;
+
+ GST_DEBUG_OBJECT (pixbufscale, "_init");
+ trans = GST_BASE_TRANSFORM (pixbufscale);
+
+ gst_pad_set_event_function (trans->srcpad, gst_pixbufscale_handle_src_event);
+
+ pixbufscale->method = GST_PIXBUFSCALE_TILES;
+ pixbufscale->gdk_method = GDK_INTERP_TILES;
+}
+
+static void
+gst_pixbufscale_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstPixbufScale *src;
+
+ g_return_if_fail (GST_IS_PIXBUFSCALE (object));
+ src = GST_PIXBUFSCALE (object);
+
+ switch (prop_id) {
+ case ARG_METHOD:
+ src->method = g_value_get_enum (value);
+ switch (src->method) {
+ case GST_PIXBUFSCALE_NEAREST:
+ src->gdk_method = GDK_INTERP_NEAREST;
+ break;
+ case GST_PIXBUFSCALE_TILES:
+ src->gdk_method = GDK_INTERP_TILES;
+ break;
+ case GST_PIXBUFSCALE_BILINEAR:
+ src->gdk_method = GDK_INTERP_BILINEAR;
+ break;
+ case GST_PIXBUFSCALE_HYPER:
+ src->gdk_method = GDK_INTERP_HYPER;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_pixbufscale_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstPixbufScale *src;
+
+ g_return_if_fail (GST_IS_PIXBUFSCALE (object));
+ src = GST_PIXBUFSCALE (object);
+
+ switch (prop_id) {
+ case ARG_METHOD:
+ g_value_set_enum (value, src->method);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+static GstCaps *
+gst_pixbufscale_transform_caps (GstBaseTransform * trans,
+ GstPadDirection direction, GstCaps * caps)
+{
+ GstCaps *ret;
+ int i;
+
+ ret = gst_caps_copy (caps);
+
+ for (i = 0; i < gst_caps_get_size (ret); i++) {
+ GstStructure *structure = gst_caps_get_structure (ret, i);
+
+ gst_structure_set (structure,
+ "width", GST_TYPE_INT_RANGE, 16, 4096,
+ "height", GST_TYPE_INT_RANGE, 16, 4096, NULL);
+ gst_structure_remove_field (structure, "pixel-aspect-ratio");
+ }
+
+ GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret);
+ return ret;
+}
+
+static gboolean
+parse_caps (GstCaps * caps, gint * width, gint * height)
+{
+ gboolean ret;
+ GstStructure *structure;
+
+ structure = gst_caps_get_structure (caps, 0);
+ ret = gst_structure_get_int (structure, "width", width);
+ ret &= gst_structure_get_int (structure, "height", height);
+
+ return ret;
+}
+
+static gboolean
+gst_pixbufscale_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
+{
+ GstPixbufScale *pixbufscale;
+ gboolean ret;
+
+ pixbufscale = GST_PIXBUFSCALE (trans);
+ ret = parse_caps (in, &pixbufscale->from_width, &pixbufscale->from_height);
+ ret &= parse_caps (out, &pixbufscale->to_width, &pixbufscale->to_height);
+ if (!ret)
+ goto done;
+
+ pixbufscale->from_stride = GST_ROUND_UP_4 (pixbufscale->from_width * 3);
+ pixbufscale->from_buf_size =
+ pixbufscale->from_stride * pixbufscale->from_height;
+
+ pixbufscale->to_stride = GST_ROUND_UP_4 (pixbufscale->to_width * 3);
+ pixbufscale->to_buf_size = pixbufscale->to_stride * pixbufscale->to_height;
+
+ GST_DEBUG_OBJECT (pixbufscale, "from=%dx%d, size %d -> to=%dx%d, size %d",
+ pixbufscale->from_width, pixbufscale->from_height,
+ pixbufscale->from_buf_size, pixbufscale->to_width, pixbufscale->to_height,
+ pixbufscale->to_buf_size);
+
+done:
+ return ret;
+}
+
+
+static gboolean
+gst_pixbufscale_get_unit_size (GstBaseTransform * trans,
+ GstCaps * caps, guint * size)
+{
+ gint width, height;
+
+ g_assert (size);
+
+ if (!parse_caps (caps, &width, &height))
+ return FALSE;
+
+ *size = GST_ROUND_UP_4 (width * 3) * height;
+
+ return TRUE;
+}
+
+static void
+gst_pixbufscale_fixate_caps (GstBaseTransform * base, GstPadDirection direction,
+ GstCaps * caps, GstCaps * othercaps)
+{
+ GstStructure *ins, *outs;
+ const GValue *from_par, *to_par;
+
+ g_return_if_fail (gst_caps_is_fixed (caps));
+
+ GST_DEBUG_OBJECT (base, "trying to fixate othercaps %" GST_PTR_FORMAT
+ " based on caps %" GST_PTR_FORMAT, othercaps, caps);
+
+ ins = gst_caps_get_structure (caps, 0);
+ outs = gst_caps_get_structure (othercaps, 0);
+
+ from_par = gst_structure_get_value (ins, "pixel-aspect-ratio");
+ to_par = gst_structure_get_value (outs, "pixel-aspect-ratio");
+
+ if (from_par && to_par) {
+ GValue to_ratio = { 0, }; /* w/h of output video */
+ int from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d;
+ int count = 0, w = 0, h = 0, num, den;
+
+ /* if both width and height are already fixed, we can't do anything
+ * * about it anymore */
+ if (gst_structure_get_int (outs, "width", &w))
+ ++count;
+ if (gst_structure_get_int (outs, "height", &h))
+ ++count;
+ if (count == 2) {
+ GST_DEBUG_OBJECT (base, "dimensions already set to %dx%d, not fixating",
+ w, h);
+ return;
+ }
+
+ gst_structure_get_int (ins, "width", &from_w);
+ gst_structure_get_int (ins, "height", &from_h);
+ from_par_n = gst_value_get_fraction_numerator (from_par);
+ from_par_d = gst_value_get_fraction_denominator (from_par);
+ to_par_n = gst_value_get_fraction_numerator (to_par);
+ to_par_d = gst_value_get_fraction_denominator (to_par);
+
+ g_value_init (&to_ratio, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&to_ratio, from_w * from_par_n * to_par_d,
+ from_h * from_par_d * to_par_n);
+ num = gst_value_get_fraction_numerator (&to_ratio);
+ den = gst_value_get_fraction_denominator (&to_ratio);
+ GST_DEBUG_OBJECT (base,
+ "scaling input with %dx%d and PAR %d/%d to output PAR %d/%d",
+ from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d);
+ GST_DEBUG_OBJECT (base,
+ "resulting output should respect ratio of %d/%d", num, den);
+
+ /* now find a width x height that respects this display ratio.
+ * * prefer those that have one of w/h the same as the incoming video
+ * * using wd / hd = num / den */
+
+ /* start with same height, because of interlaced video */
+ /* check hd / den is an integer scale factor, and scale wd with the PAR */
+ if (from_h % den == 0) {
+ GST_DEBUG_OBJECT (base, "keeping video height");
+ h = from_h;
+ w = h * num / den;
+ } else if (from_w % num == 0) {
+ GST_DEBUG_OBJECT (base, "keeping video width");
+ w = from_w;
+ h = w * den / num;
+ } else {
+ GST_DEBUG_OBJECT (base, "approximating but keeping video height");
+ h = from_h;
+ w = h * num / den;
+ }
+ GST_DEBUG_OBJECT (base, "scaling to %dx%d", w, h);
+ /* now fixate */
+ gst_structure_fixate_field_nearest_int (outs, "width", w);
+ gst_structure_fixate_field_nearest_int (outs, "height", h);
+ } else {
+ gint width, height;
+
+ if (gst_structure_get_int (ins, "width", &width)) {
+ if (gst_structure_has_field (outs, "width")) {
+ gst_structure_fixate_field_nearest_int (outs, "width", width);
+ }
+ }
+ if (gst_structure_get_int (ins, "height", &height)) {
+ if (gst_structure_has_field (outs, "height")) {
+ gst_structure_fixate_field_nearest_int (outs, "height", height);
+ }
+ }
+ }
+
+ GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
+}
+
+static GstFlowReturn
+gst_pixbufscale_transform (GstBaseTransform * trans,
+ GstBuffer * in, GstBuffer * out)
+{
+ GstPixbufScale *scale;
+ GdkPixbuf *src_pixbuf, *dest_pixbuf;
+
+ scale = GST_PIXBUFSCALE (trans);
+
+ src_pixbuf =
+ gdk_pixbuf_new_from_data (GST_BUFFER_DATA (in), GDK_COLORSPACE_RGB, FALSE,
+ 8, scale->from_width, scale->from_height,
+ GST_RGB24_ROWSTRIDE (scale->from_width), NULL, NULL);
+
+ dest_pixbuf =
+ gdk_pixbuf_new_from_data (GST_BUFFER_DATA (out), GDK_COLORSPACE_RGB,
+ FALSE, 8, scale->to_width, scale->to_height,
+ GST_RGB24_ROWSTRIDE (scale->to_width), NULL, NULL);
+
+ gdk_pixbuf_scale (src_pixbuf, dest_pixbuf, 0, 0,
+ scale->to_width,
+ scale->to_height, 0, 0,
+ (double) scale->to_width / scale->from_width,
+ (double) scale->to_height / scale->from_height, scale->gdk_method);
+
+ g_object_unref (src_pixbuf);
+ g_object_unref (dest_pixbuf);
+
+ return GST_FLOW_OK;
+}
+
+static gboolean
+gst_pixbufscale_handle_src_event (GstPad * pad, GstEvent * event)
+{
+ GstPixbufScale *pixbufscale;
+ gboolean ret;
+ double a;
+ GstStructure *structure;
+
+ pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad));
+
+ GST_DEBUG_OBJECT (pixbufscale, "handling %s event",
+ GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_NAVIGATION:
+ event =
+ GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
+
+ structure = (GstStructure *) gst_event_get_structure (event);
+ if (gst_structure_get_double (structure, "pointer_x", &a)) {
+ gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
+ a * pixbufscale->from_width / pixbufscale->to_width, NULL);
+ }
+ if (gst_structure_get_double (structure, "pointer_y", &a)) {
+ gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
+ a * pixbufscale->from_height / pixbufscale->to_height, NULL);
+ }
+ break;
+ default:
+ break;
+ }
+
+ ret = gst_pad_event_default (pad, event);
+
+ gst_object_unref (pixbufscale);
+
+ return ret;
+}
+
+gboolean
+pixbufscale_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "gdkpixbufscale", GST_RANK_NONE,
+ GST_TYPE_PIXBUFSCALE))
+ return FALSE;
+
+ GST_DEBUG_CATEGORY_INIT (pixbufscale_debug, "gdkpixbufscale", 0,
+ "pixbufscale element");
+
+ return TRUE;
+}
diff --git a/ext/gdk_pixbuf/pixbufscale.h b/ext/gdk_pixbuf/pixbufscale.h
new file mode 100644
index 0000000..3e40477
--- /dev/null
+++ b/ext/gdk_pixbuf/pixbufscale.h
@@ -0,0 +1,84 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2004> Jan Schmidt <thaytan@mad.scientist.com>
+ * Copyright (C) <2004> Tim-Philipp Mueller <t.i.m@orange.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_PIXBUFSCALE_H__
+#define __GST_PIXBUFSCALE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PIXBUFSCALE \
+ (gst_pixbufscale_get_type())
+#define GST_PIXBUFSCALE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PIXBUFSCALE,GstPixbufScale))
+#define GST_PIXBUFSCALE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PIXBUFSCALE,GstPixbufScaleClass))
+#define GST_IS_PIXBUFSCALE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PIXBUFSCALE))
+#define GST_IS_PIXBUFSCALE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PIXBUFSCALE))
+
+typedef enum {
+ GST_PIXBUFSCALE_NEAREST,
+ GST_PIXBUFSCALE_TILES,
+ GST_PIXBUFSCALE_BILINEAR,
+ GST_PIXBUFSCALE_HYPER
+} GstPixbufScaleMethod;
+
+
+typedef struct _GstPixbufScale GstPixbufScale;
+typedef struct _GstPixbufScaleClass GstPixbufScaleClass;
+
+struct _GstPixbufScale {
+ GstBaseTransform element;
+
+ /* video state */
+ gint to_width;
+ gint to_height;
+ gint from_width;
+ gint from_height;
+ gboolean passthru;
+
+ GstPixbufScaleMethod method;
+ GdkInterpType gdk_method;
+
+ /* private */
+ gint from_buf_size;
+ gint from_stride;
+ gint to_buf_size;
+ gint to_stride;
+};
+
+struct _GstPixbufScaleClass {
+ GstBaseTransformClass parent_class;
+};
+
+GType gst_pixbufscale_get_type(void);
+
+gboolean pixbufscale_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_PIXBUFSCALE_H__ */
diff --git a/ext/hal/Makefile.am b/ext/hal/Makefile.am
new file mode 100644
index 0000000..8862aeb
--- /dev/null
+++ b/ext/hal/Makefile.am
@@ -0,0 +1,18 @@
+plugin_LTLIBRARIES = libgsthalelements.la
+
+libgsthalelements_la_SOURCES = \
+ gsthalaudiosink.c \
+ gsthalaudiosrc.c \
+ gsthalelements.c \
+ hal.c
+
+libgsthalelements_la_CFLAGS = $(GST_CFLAGS) $(HAL_CFLAGS)
+libgsthalelements_la_LIBADD = $(GST_LIBS) $(HAL_LIBS)
+libgsthalelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgsthalelements_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = \
+ gsthalaudiosink.h \
+ gsthalaudiosrc.h \
+ gsthalelements.h \
+ hal.h
diff --git a/ext/hal/Makefile.in b/ext/hal/Makefile.in
new file mode 100644
index 0000000..7a67203
--- /dev/null
+++ b/ext/hal/Makefile.in
@@ -0,0 +1,843 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/hal
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgsthalelements_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgsthalelements_la_OBJECTS = \
+ libgsthalelements_la-gsthalaudiosink.lo \
+ libgsthalelements_la-gsthalaudiosrc.lo \
+ libgsthalelements_la-gsthalelements.lo \
+ libgsthalelements_la-hal.lo
+libgsthalelements_la_OBJECTS = $(am_libgsthalelements_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgsthalelements_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgsthalelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(libgsthalelements_la_CFLAGS) $(CFLAGS) \
+ $(libgsthalelements_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgsthalelements_la_SOURCES)
+DIST_SOURCES = $(libgsthalelements_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgsthalelements.la
+libgsthalelements_la_SOURCES = \
+ gsthalaudiosink.c \
+ gsthalaudiosrc.c \
+ gsthalelements.c \
+ hal.c
+
+libgsthalelements_la_CFLAGS = $(GST_CFLAGS) $(HAL_CFLAGS)
+libgsthalelements_la_LIBADD = $(GST_LIBS) $(HAL_LIBS)
+libgsthalelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgsthalelements_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = \
+ gsthalaudiosink.h \
+ gsthalaudiosrc.h \
+ gsthalelements.h \
+ hal.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/hal/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/hal/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgsthalelements.la: $(libgsthalelements_la_OBJECTS) $(libgsthalelements_la_DEPENDENCIES) $(EXTRA_libgsthalelements_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgsthalelements_la_LINK) -rpath $(plugindir) $(libgsthalelements_la_OBJECTS) $(libgsthalelements_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsthalelements_la-gsthalaudiosink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsthalelements_la-gsthalaudiosrc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsthalelements_la-gsthalelements.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsthalelements_la-hal.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgsthalelements_la-gsthalaudiosink.lo: gsthalaudiosink.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgsthalelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsthalelements_la_CFLAGS) $(CFLAGS) -MT libgsthalelements_la-gsthalaudiosink.lo -MD -MP -MF $(DEPDIR)/libgsthalelements_la-gsthalaudiosink.Tpo -c -o libgsthalelements_la-gsthalaudiosink.lo `test -f 'gsthalaudiosink.c' || echo '$(srcdir)/'`gsthalaudiosink.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgsthalelements_la-gsthalaudiosink.Tpo $(DEPDIR)/libgsthalelements_la-gsthalaudiosink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gsthalaudiosink.c' object='libgsthalelements_la-gsthalaudiosink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgsthalelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsthalelements_la_CFLAGS) $(CFLAGS) -c -o libgsthalelements_la-gsthalaudiosink.lo `test -f 'gsthalaudiosink.c' || echo '$(srcdir)/'`gsthalaudiosink.c
+
+libgsthalelements_la-gsthalaudiosrc.lo: gsthalaudiosrc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgsthalelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsthalelements_la_CFLAGS) $(CFLAGS) -MT libgsthalelements_la-gsthalaudiosrc.lo -MD -MP -MF $(DEPDIR)/libgsthalelements_la-gsthalaudiosrc.Tpo -c -o libgsthalelements_la-gsthalaudiosrc.lo `test -f 'gsthalaudiosrc.c' || echo '$(srcdir)/'`gsthalaudiosrc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgsthalelements_la-gsthalaudiosrc.Tpo $(DEPDIR)/libgsthalelements_la-gsthalaudiosrc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gsthalaudiosrc.c' object='libgsthalelements_la-gsthalaudiosrc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgsthalelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsthalelements_la_CFLAGS) $(CFLAGS) -c -o libgsthalelements_la-gsthalaudiosrc.lo `test -f 'gsthalaudiosrc.c' || echo '$(srcdir)/'`gsthalaudiosrc.c
+
+libgsthalelements_la-gsthalelements.lo: gsthalelements.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgsthalelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsthalelements_la_CFLAGS) $(CFLAGS) -MT libgsthalelements_la-gsthalelements.lo -MD -MP -MF $(DEPDIR)/libgsthalelements_la-gsthalelements.Tpo -c -o libgsthalelements_la-gsthalelements.lo `test -f 'gsthalelements.c' || echo '$(srcdir)/'`gsthalelements.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgsthalelements_la-gsthalelements.Tpo $(DEPDIR)/libgsthalelements_la-gsthalelements.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gsthalelements.c' object='libgsthalelements_la-gsthalelements.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgsthalelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsthalelements_la_CFLAGS) $(CFLAGS) -c -o libgsthalelements_la-gsthalelements.lo `test -f 'gsthalelements.c' || echo '$(srcdir)/'`gsthalelements.c
+
+libgsthalelements_la-hal.lo: hal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgsthalelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsthalelements_la_CFLAGS) $(CFLAGS) -MT libgsthalelements_la-hal.lo -MD -MP -MF $(DEPDIR)/libgsthalelements_la-hal.Tpo -c -o libgsthalelements_la-hal.lo `test -f 'hal.c' || echo '$(srcdir)/'`hal.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgsthalelements_la-hal.Tpo $(DEPDIR)/libgsthalelements_la-hal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hal.c' object='libgsthalelements_la-hal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgsthalelements_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsthalelements_la_CFLAGS) $(CFLAGS) -c -o libgsthalelements_la-hal.lo `test -f 'hal.c' || echo '$(srcdir)/'`hal.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/hal/gsthalaudiosink.c b/ext/hal/gsthalaudiosink.c
new file mode 100644
index 0000000..88fac00
--- /dev/null
+++ b/ext/hal/gsthalaudiosink.c
@@ -0,0 +1,250 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2006 Jürg Billeter <j@bitron.ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-halaudiosink
+ *
+ * HalAudioSink allows access to output of sound devices by specifying the
+ * corresponding persistent Unique Device Id (UDI) from the Hardware Abstraction
+ * Layer (HAL) in the #GstHalAudioSink:udi property.
+ * It currently always embeds alsasink or osssink as HAL doesn't support other
+ * sound systems yet. You can also specify the UDI of a device that has ALSA or
+ * OSS subdevices. If both are present ALSA is preferred.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * hal-find-by-property --key alsa.type --string playback
+ * ]| list the UDIs of all your ALSA output devices
+ * |[
+ * gst-launch -v audiotestsrc ! halaudiosink udi=/org/freedesktop/Hal/devices/pci_8086_27d8_alsa_playback_0
+ * ]| test your soundcard by playing a test signal on the specified sound device.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gsthalelements.h"
+#include "gsthalaudiosink.h"
+
+static void gst_hal_audio_sink_dispose (GObject * object);
+static GstStateChangeReturn
+gst_hal_audio_sink_change_state (GstElement * element,
+ GstStateChange transition);
+
+enum
+{
+ PROP_0,
+ PROP_UDI
+};
+
+GST_BOILERPLATE (GstHalAudioSink, gst_hal_audio_sink, GstBin, GST_TYPE_BIN);
+
+static void gst_hal_audio_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_hal_audio_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void
+gst_hal_audio_sink_base_init (gpointer klass)
+{
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+ gst_element_class_add_static_pad_template (eklass, &sink_template);
+ gst_element_class_set_details_simple (eklass, "HAL audio sink",
+ "Sink/Audio",
+ "Audio sink for sound device access via HAL",
+ "Jürg Billeter <j@bitron.ch>");
+}
+
+static void
+gst_hal_audio_sink_class_init (GstHalAudioSinkClass * klass)
+{
+ GObjectClass *oklass = G_OBJECT_CLASS (klass);
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ oklass->set_property = gst_hal_audio_sink_set_property;
+ oklass->get_property = gst_hal_audio_sink_get_property;
+ oklass->dispose = gst_hal_audio_sink_dispose;
+ eklass->change_state = gst_hal_audio_sink_change_state;
+
+ g_object_class_install_property (oklass, PROP_UDI,
+ g_param_spec_string ("udi",
+ "UDI", "Unique Device Id", NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+/*
+ * Hack to make negotiation work.
+ */
+
+static void
+gst_hal_audio_sink_reset (GstHalAudioSink * sink)
+{
+ GstPad *targetpad;
+
+ /* fakesink */
+ if (sink->kid) {
+ gst_element_set_state (sink->kid, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN (sink), sink->kid);
+ }
+ sink->kid = gst_element_factory_make ("fakesink", "testsink");
+ gst_bin_add (GST_BIN (sink), sink->kid);
+
+ targetpad = gst_element_get_static_pad (sink->kid, "sink");
+ gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
+ gst_object_unref (targetpad);
+}
+
+static void
+gst_hal_audio_sink_init (GstHalAudioSink * sink, GstHalAudioSinkClass * g_class)
+{
+ sink->pad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
+ gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
+
+ gst_hal_audio_sink_reset (sink);
+}
+
+static void
+gst_hal_audio_sink_dispose (GObject * object)
+{
+ GstHalAudioSink *sink = GST_HAL_AUDIO_SINK (object);
+
+ if (sink->udi) {
+ g_free (sink->udi);
+ sink->udi = NULL;
+ }
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static gboolean
+do_toggle_element (GstHalAudioSink * sink)
+{
+ GstPad *targetpad;
+
+ /* kill old element */
+ if (sink->kid) {
+ GST_DEBUG_OBJECT (sink, "Removing old kid");
+ gst_element_set_state (sink->kid, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN (sink), sink->kid);
+ sink->kid = NULL;
+ }
+
+ GST_DEBUG_OBJECT (sink, "Creating new kid");
+ if (!sink->udi)
+ GST_INFO_OBJECT (sink, "No UDI set for device, using default one");
+
+ if (!(sink->kid = gst_hal_get_audio_sink (sink->udi))) {
+ GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL),
+ ("Failed to render audio sink from Hal"));
+ return FALSE;
+ }
+ gst_element_set_state (sink->kid, GST_STATE (sink));
+ gst_bin_add (GST_BIN (sink), sink->kid);
+
+ /* re-attach ghostpad */
+ GST_DEBUG_OBJECT (sink, "Creating new ghostpad");
+ targetpad = gst_element_get_static_pad (sink->kid, "sink");
+ gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
+ gst_object_unref (targetpad);
+ GST_DEBUG_OBJECT (sink, "done changing hal audio sink");
+
+ return TRUE;
+}
+
+static void
+gst_hal_audio_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstHalAudioSink *this = GST_HAL_AUDIO_SINK (object);
+
+ GST_OBJECT_LOCK (this);
+
+ switch (prop_id) {
+ case PROP_UDI:
+ if (this->udi)
+ g_free (this->udi);
+ this->udi = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ GST_OBJECT_UNLOCK (this);
+}
+
+static void
+gst_hal_audio_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstHalAudioSink *this = GST_HAL_AUDIO_SINK (object);
+
+ GST_OBJECT_LOCK (this);
+
+ switch (prop_id) {
+ case PROP_UDI:
+ g_value_set_string (value, this->udi);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ GST_OBJECT_UNLOCK (this);
+}
+
+static GstStateChangeReturn
+gst_hal_audio_sink_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstHalAudioSink *sink = GST_HAL_AUDIO_SINK (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!do_toggle_element (sink))
+ return GST_STATE_CHANGE_FAILURE;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
+ (element, transition), GST_STATE_CHANGE_SUCCESS);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ gst_hal_audio_sink_reset (sink);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/hal/gsthalaudiosink.h b/ext/hal/gsthalaudiosink.h
new file mode 100644
index 0000000..3f07fde
--- /dev/null
+++ b/ext/hal/gsthalaudiosink.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2006 Jürg Billeter <j@bitron.ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_HAL_AUDIO_SINK_H__
+#define __GST_HAL_AUDIO_SINK_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_HAL_AUDIO_SINK \
+ (gst_hal_audio_sink_get_type ())
+#define GST_HAL_AUDIO_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_HAL_AUDIO_SINK, \
+ GstHalAudioSink))
+#define GST_HAL_AUDIO_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_HAL_AUDIO_SINK, \
+ GstHalAudioSinkClass))
+#define GST_IS_HAL_AUDIO_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_HAL_AUDIO_SINK))
+#define GST_IS_HAL_AUDIO_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_HAL_AUDIO_SINK))
+
+typedef struct _GstHalAudioSink {
+ GstBin parent;
+
+ /* explicit pointers to stuff used */
+ gchar *udi;
+ GstElement *kid;
+ GstPad *pad;
+} GstHalAudioSink;
+
+typedef struct _GstHalAudioSinkClass {
+ GstBinClass parent_class;
+} GstHalAudioSinkClass;
+
+GType gst_hal_audio_sink_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_HAL_AUDIO_SINK_H__ */
diff --git a/ext/hal/gsthalaudiosrc.c b/ext/hal/gsthalaudiosrc.c
new file mode 100644
index 0000000..339a767
--- /dev/null
+++ b/ext/hal/gsthalaudiosrc.c
@@ -0,0 +1,251 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2005 Tim-Philipp Müller <tim centricular net>
+ * (c) 2006 Jürg Billeter <j@bitron.ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-halaudiosrc
+ *
+ * HalAudioSrc allows access to input of sound devices by specifying the
+ * corresponding persistent Unique Device Id (UDI) from the Hardware Abstraction
+ * Layer (HAL) in the #GstHalAudioSrc:udi property.
+ * It currently always embeds alsasrc or osssrc as HAL doesn't support other
+ * sound systems yet. You can also specify the UDI of a device that has ALSA or
+ * OSS subdevices. If both are present ALSA is preferred.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * hal-find-by-property --key alsa.type --string capture
+ * ]| list the UDIs of all your ALSA input devices
+ * |[
+ * gst-launch -v halaudiosrc udi=/org/freedesktop/Hal/devices/pci_8086_27d8_alsa_capture_0 ! autoaudiosink
+ * ]| You should now hear yourself with a small delay if you have a microphone
+ * connected to the specified sound device.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gsthalelements.h"
+#include "gsthalaudiosrc.h"
+
+static void gst_hal_audio_src_dispose (GObject * object);
+static GstStateChangeReturn
+gst_hal_audio_src_change_state (GstElement * element,
+ GstStateChange transition);
+
+enum
+{
+ PROP_0,
+ PROP_UDI
+};
+
+GST_BOILERPLATE (GstHalAudioSrc, gst_hal_audio_src, GstBin, GST_TYPE_BIN);
+
+static void gst_hal_audio_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_hal_audio_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void
+gst_hal_audio_src_base_init (gpointer klass)
+{
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+ gst_element_class_add_static_pad_template (eklass, &src_template);
+ gst_element_class_set_details_simple (eklass, "HAL audio source",
+ "Source/Audio",
+ "Audio source for sound device access via HAL",
+ "Jürg Billeter <j@bitron.ch>");
+}
+
+static void
+gst_hal_audio_src_class_init (GstHalAudioSrcClass * klass)
+{
+ GObjectClass *oklass = G_OBJECT_CLASS (klass);
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ oklass->set_property = gst_hal_audio_src_set_property;
+ oklass->get_property = gst_hal_audio_src_get_property;
+ oklass->dispose = gst_hal_audio_src_dispose;
+ eklass->change_state = gst_hal_audio_src_change_state;
+
+ g_object_class_install_property (oklass, PROP_UDI,
+ g_param_spec_string ("udi",
+ "UDI", "Unique Device Id", NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+/*
+ * Hack to make negotiation work.
+ */
+
+static void
+gst_hal_audio_src_reset (GstHalAudioSrc * src)
+{
+ GstPad *targetpad;
+
+ /* fakesrc */
+ if (src->kid) {
+ gst_element_set_state (src->kid, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN (src), src->kid);
+ }
+ src->kid = gst_element_factory_make ("fakesrc", "testsrc");
+ gst_bin_add (GST_BIN (src), src->kid);
+
+ targetpad = gst_element_get_static_pad (src->kid, "src");
+ gst_ghost_pad_set_target (GST_GHOST_PAD (src->pad), targetpad);
+ gst_object_unref (targetpad);
+}
+
+static void
+gst_hal_audio_src_init (GstHalAudioSrc * src, GstHalAudioSrcClass * g_class)
+{
+ src->pad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC);
+ gst_element_add_pad (GST_ELEMENT (src), src->pad);
+
+ gst_hal_audio_src_reset (src);
+}
+
+static void
+gst_hal_audio_src_dispose (GObject * object)
+{
+ GstHalAudioSrc *src = GST_HAL_AUDIO_SRC (object);
+
+ if (src->udi) {
+ g_free (src->udi);
+ src->udi = NULL;
+ }
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static gboolean
+do_toggle_element (GstHalAudioSrc * src)
+{
+ GstPad *targetpad;
+
+ /* kill old element */
+ if (src->kid) {
+ GST_DEBUG_OBJECT (src, "Removing old kid");
+ gst_element_set_state (src->kid, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN (src), src->kid);
+ src->kid = NULL;
+ }
+
+ GST_DEBUG_OBJECT (src, "Creating new kid");
+ if (!src->udi)
+ GST_INFO_OBJECT (src, "No UDI set for device, using default one");
+
+ if (!(src->kid = gst_hal_get_audio_src (src->udi))) {
+ GST_ELEMENT_ERROR (src, LIBRARY, SETTINGS, (NULL),
+ ("Failed to render audio source from Hal"));
+ return FALSE;
+ }
+ gst_element_set_state (src->kid, GST_STATE (src));
+ gst_bin_add (GST_BIN (src), src->kid);
+
+ /* re-attach ghostpad */
+ GST_DEBUG_OBJECT (src, "Creating new ghostpad");
+ targetpad = gst_element_get_static_pad (src->kid, "src");
+ gst_ghost_pad_set_target (GST_GHOST_PAD (src->pad), targetpad);
+ gst_object_unref (targetpad);
+ GST_DEBUG_OBJECT (src, "done changing hal audio source");
+
+ return TRUE;
+}
+
+static void
+gst_hal_audio_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstHalAudioSrc *this = GST_HAL_AUDIO_SRC (object);
+
+ GST_OBJECT_LOCK (this);
+
+ switch (prop_id) {
+ case PROP_UDI:
+ if (this->udi)
+ g_free (this->udi);
+ this->udi = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ GST_OBJECT_UNLOCK (this);
+}
+
+static void
+gst_hal_audio_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstHalAudioSrc *this = GST_HAL_AUDIO_SRC (object);
+
+ GST_OBJECT_LOCK (this);
+
+ switch (prop_id) {
+ case PROP_UDI:
+ g_value_set_string (value, this->udi);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ GST_OBJECT_UNLOCK (this);
+}
+
+static GstStateChangeReturn
+gst_hal_audio_src_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstHalAudioSrc *src = GST_HAL_AUDIO_SRC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!do_toggle_element (src))
+ return GST_STATE_CHANGE_FAILURE;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
+ (element, transition), GST_STATE_CHANGE_SUCCESS);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ gst_hal_audio_src_reset (src);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/hal/gsthalaudiosrc.h b/ext/hal/gsthalaudiosrc.h
new file mode 100644
index 0000000..7afdadd
--- /dev/null
+++ b/ext/hal/gsthalaudiosrc.h
@@ -0,0 +1,52 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2005 Tim-Philipp Müller <tim centricular net>
+ * (c) 2006 Jürg Billeter <j@bitron.ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_HAL_AUDIO_SRC_H__
+#define __GST_HAL_AUDIO_SRC_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_HAL_AUDIO_SRC (gst_hal_audio_src_get_type ())
+#define GST_HAL_AUDIO_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_HAL_AUDIO_SRC, GstHalAudioSrc))
+#define GST_HAL_AUDIO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_HAL_AUDIO_SRC, GstHalAudioSrcClass))
+#define GST_IS_HAL_AUDIO_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_HAL_AUDIO_SRC))
+#define GST_IS_HAL_AUDIO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_HAL_AUDIO_SRC))
+
+typedef struct _GstHalAudioSrc {
+ GstBin parent;
+
+ /* explicit pointers to stuff used */
+ gchar *udi;
+ GstElement *kid;
+ GstPad *pad;
+} GstHalAudioSrc;
+
+typedef struct _GstHalAudioSrcClass {
+ GstBinClass parent_class;
+} GstHalAudioSrcClass;
+
+GType gst_hal_audio_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_HAL_AUDIO_SRC_H__ */
diff --git a/ext/hal/gsthalelements.c b/ext/hal/gsthalelements.c
new file mode 100644
index 0000000..dd5122a
--- /dev/null
+++ b/ext/hal/gsthalelements.c
@@ -0,0 +1,54 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2006 Jürg Billeter <j@bitron.ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "gsthalelements.h"
+
+#include "gsthalaudiosink.h"
+#include "gsthalaudiosrc.h"
+
+GST_DEBUG_CATEGORY (hal_debug);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (hal_debug, "hal", 0,
+ "HAL/GStreamer audio input/output wrapper elements");
+
+ if (!gst_element_register (plugin, "halaudiosink",
+ GST_RANK_NONE, GST_TYPE_HAL_AUDIO_SINK) ||
+ !gst_element_register (plugin, "halaudiosrc",
+ GST_RANK_NONE, GST_TYPE_HAL_AUDIO_SRC)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "halelements",
+ "elements wrapping the GStreamer/HAL audio input/output devices",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/hal/gsthalelements.h b/ext/hal/gsthalelements.h
new file mode 100644
index 0000000..6a9462f
--- /dev/null
+++ b/ext/hal/gsthalelements.h
@@ -0,0 +1,29 @@
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2006 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_HAL_ELEMENTS_H__
+#define __GST_HAL_ELEMENTS_H__
+
+#include <hal.h>
+
+GST_DEBUG_CATEGORY_EXTERN (hal_debug);
+#define GST_CAT_DEFAULT hal_debug
+
+#endif /* __GST_HAL_ELEMENTS_H__ */
diff --git a/ext/hal/hal.c b/ext/hal/hal.c
new file mode 100644
index 0000000..6957f56
--- /dev/null
+++ b/ext/hal/hal.c
@@ -0,0 +1,397 @@
+/* GStreamer
+ * Copyright (C) <2002> Thomas Vander Stichele <thomas@apestaart.org>
+ * Copyright (C) <2006> Jürg Billeter <j@bitron.ch>
+ * Copyright (C) <2007> Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * this library handles interaction with Hal
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <glib.h>
+#include "hal.h"
+
+GST_DEBUG_CATEGORY_EXTERN (hal_debug);
+
+#define GST_CAT_DEFAULT hal_debug
+
+/* compat for older libhal */
+#ifndef LIBHAL_FREE_DBUS_ERROR
+#define LIBHAL_FREE_DBUS_ERROR(e) dbus_error_free (e)
+#endif
+
+/*
+ * gst_hal_get_alsa_element:
+ * @ctx: a #LibHalContext which should be used for querying HAL.
+ * @udi: a #gchar corresponding to the UDI you want to get.
+ * @device_type: a #GstHalDeviceType specifying the wanted device type.
+ *
+ * Get Hal UDI @udi's string value.
+ *
+ * Returns: a newly allocated #gchar string containing the appropriate pipeline
+ * for UDI @udi, or NULL in the case of an error..
+ */
+static gchar *
+gst_hal_get_alsa_element (LibHalContext * ctx, const gchar * udi,
+ GstHalDeviceType device_type)
+{
+ char *type, *string = NULL;
+ const char *element = NULL;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ if (!libhal_device_query_capability (ctx, udi, "alsa", &error)) {
+ if (dbus_error_is_set (&error)) {
+ GST_DEBUG ("Failed querying %s for alsa capability: %s: %s",
+ udi, error.name, error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ } else {
+ GST_DEBUG ("UDI %s has no alsa capability", udi);
+ }
+ return NULL;
+ }
+
+ type = libhal_device_get_property_string (ctx, udi, "alsa.type", &error);
+
+ if (dbus_error_is_set (&error)) {
+ GST_DEBUG ("UDI %s has alsa capabilities but no alsa.type property: %s, %s",
+ udi, error.name, error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ return NULL;
+ } else if (!type) {
+ GST_DEBUG ("UDI %s has empty alsa.type property", udi);
+ return NULL;
+ }
+
+ if (strcmp (type, "playback") == 0 && device_type == GST_HAL_AUDIOSINK)
+ element = "alsasink";
+ else if (strcmp (type, "capture") == 0 && device_type == GST_HAL_AUDIOSRC)
+ element = "alsasrc";
+
+ libhal_free_string (type);
+
+ if (element) {
+ int card, device;
+
+ card = libhal_device_get_property_int (ctx, udi, "alsa.card", &error);
+ if (dbus_error_is_set (&error)) {
+ GST_DEBUG ("UDI %s has no alsa.card property: %s: %s", udi, error.name,
+ error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ return NULL;
+ } else if (card == -1) {
+ GST_DEBUG ("UDI %s has no alsa.card property", udi);
+ return NULL;
+ }
+
+ device = libhal_device_get_property_int (ctx, udi, "alsa.device", &error);
+ if (dbus_error_is_set (&error)) {
+ GST_DEBUG ("UDI %s has no alsa.device property: %s: %s", udi, error.name,
+ error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ return NULL;
+ } else if (device == -1) {
+ GST_DEBUG ("UDI %s has no alsa.device property", udi);
+ return NULL;
+ }
+
+ /* This is a bit dodgy, since it makes lots of assumptions about the way
+ * alsa is set up. In any case, only munge the device string for playback */
+ if (strcmp (element, "alsasink") == 0 && device == 0) {
+ /* handle default device specially to use
+ * dmix, dsnoop, and softvol if appropriate */
+ string = g_strdup_printf ("%s device=default:%d", element, card);
+ } else {
+ string =
+ g_strdup_printf ("%s device=plughw:%d,%d", element, card, device);
+ }
+ }
+
+ return string;
+}
+
+/*
+ * gst_hal_get_oss_element:
+ * @ctx: a #LibHalContext which should be used for querying HAL.
+ * @udi: a #gchar corresponding to the UDI you want to get.
+ * @device_type: a #GstHalDeviceType specifying the wanted device type.
+ *
+ * Get Hal UDI @udi's string value.
+ *
+ * Returns: a newly allocated #gchar string containing the appropriate pipeline
+ * for UDI @udi, or NULL in the case of an error..
+ */
+static gchar *
+gst_hal_get_oss_element (LibHalContext * ctx, const gchar * udi,
+ GstHalDeviceType device_type)
+{
+ char *type, *string = NULL;
+ const char *element = NULL;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ if (!libhal_device_query_capability (ctx, udi, "oss", &error)) {
+ if (dbus_error_is_set (&error)) {
+ GST_DEBUG ("Failed querying %s for oss capability: %s: %s", udi,
+ error.name, error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ } else {
+ GST_DEBUG ("UDI %s has no oss capability", udi);
+ }
+ return NULL;
+ }
+
+ type = libhal_device_get_property_string (ctx, udi, "oss.type", &error);
+ if (dbus_error_is_set (&error)) {
+ GST_DEBUG ("UDI %s has oss capabilities but no oss.type property: %s, %s",
+ udi, error.name, error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ return NULL;
+ } else if (!type) {
+ GST_DEBUG ("UDI %s has empty oss.type property", udi);
+ return NULL;
+ }
+
+ if (strcmp (type, "pcm") == 0) {
+ if (device_type == GST_HAL_AUDIOSINK)
+ element = "osssink";
+ else if (device_type == GST_HAL_AUDIOSRC)
+ element = "osssrc";
+ }
+ libhal_free_string (type);
+
+ if (element) {
+ char *device = NULL;
+
+ device =
+ libhal_device_get_property_string (ctx, udi, "oss.device_file", &error);
+ if (dbus_error_is_set (&error)) {
+ GST_DEBUG
+ ("UDI %s has oss capabilities but no oss.device_file property: %s, %s",
+ udi, error.name, error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ return NULL;
+ } else if (!device) {
+ GST_DEBUG ("UDI %s has empty oss.device_file property", udi);
+ return NULL;
+ }
+
+ string = g_strdup_printf ("%s device=%s", element, device);
+ libhal_free_string (device);
+ }
+
+ return string;
+}
+
+/*
+ * gst_hal_get_string:
+ * @udi: a #gchar corresponding to the UDI you want to get.
+ * @device_type: a #GstHalDeviceType specifying the wanted device type.
+ *
+ * Get Hal UDI @udi's string value.
+ *
+ * Returns: a newly allocated #gchar string containing the appropriate pipeline
+ * for UDI @udi, or NULL in the case of an error..
+ */
+static gchar *
+gst_hal_get_string (const gchar * udi, GstHalDeviceType device_type)
+{
+ DBusError error;
+ LibHalContext *ctx;
+ char *string = NULL;
+
+ /* Don't query HAL for NULL UDIs. Passing NULL as UDI to HAL gives
+ * an assertion failure in D-Bus when running with
+ * DBUS_FATAL_WARNINGS=1. */
+ if (!udi)
+ return NULL;
+
+ dbus_error_init (&error);
+
+ ctx = libhal_ctx_new ();
+ /* Should only happen on OOM */
+ g_return_val_if_fail (ctx != NULL, NULL);
+
+ if (!libhal_ctx_set_dbus_connection (ctx, dbus_bus_get (DBUS_BUS_SYSTEM,
+ &error))) {
+ GST_DEBUG ("Unable to set DBus connection: %s: %s", error.name,
+ error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ goto ctx_free;
+ }
+
+ if (!libhal_ctx_init (ctx, &error)) {
+ GST_DEBUG ("Unable to set init HAL context: %s: %s", error.name,
+ error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ goto ctx_free;
+ }
+
+ /* Now first check if UDI is an alsa device, then oss and then
+ * check the childs of the given device. If there are alsa and oss
+ * children the first alsa one is used. */
+
+ string = gst_hal_get_alsa_element (ctx, udi, device_type);
+
+ if (!string)
+ string = gst_hal_get_oss_element (ctx, udi, device_type);
+
+ if (!string) {
+ int num_childs;
+ char **childs = NULL;
+
+ /* now try if one of the direct subdevices supports ALSA or OSS */
+ childs =
+ libhal_manager_find_device_string_match (ctx, "info.parent", udi,
+ &num_childs, &error);
+ if (dbus_error_is_set (&error)) {
+ GST_DEBUG ("Unable to retrieve childs of %s: %s: %s", udi, error.name,
+ error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ goto ctx_shutdown;
+ }
+
+ if (childs && num_childs > 0) {
+ int i;
+ char *alsa_string = NULL, *oss_string = NULL;
+
+ for (i = 0; i < num_childs && !alsa_string; i++) {
+ alsa_string = gst_hal_get_alsa_element (ctx, childs[i], device_type);
+
+ if (!oss_string)
+ oss_string = gst_hal_get_oss_element (ctx, childs[i], device_type);
+ }
+
+ if (alsa_string) {
+ string = alsa_string;
+ g_free (oss_string);
+ } else if (oss_string) {
+ string = oss_string;
+ }
+ }
+ libhal_free_string_array (childs);
+ }
+
+ctx_shutdown:
+ if (!libhal_ctx_shutdown (ctx, &error)) {
+ GST_DEBUG ("Closing connection to HAL failed: %s: %s", error.name,
+ error.message);
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ }
+
+ctx_free:
+ libhal_ctx_free (ctx);
+
+ if (string == NULL) {
+ GST_WARNING ("Problem finding a HAL audio device for udi %s", udi);
+ } else {
+ GST_INFO ("Using %s", string);
+ }
+
+ return string;
+}
+
+/* external functions */
+
+/**
+ * gst_hal_render_bin_from_udi:
+ * @udi: a #gchar string corresponding to a Hal UDI.
+ *
+ * Render bin from Hal UDI @udi.
+ *
+ * Returns: a #GstElement containing the rendered bin.
+ */
+GstElement *
+gst_hal_render_bin_from_udi (const gchar * udi, GstHalDeviceType type)
+{
+ GstElement *bin = NULL;
+ gchar *value;
+
+ value = gst_hal_get_string (udi, type);
+ if (value)
+ bin = gst_parse_bin_from_description (value, TRUE, NULL);
+ g_free (value);
+ return bin;
+}
+
+/**
+ * gst_hal_get_audio_sink:
+ * @udi: a #gchar string corresponding to a Hal UDI.
+ *
+ * Render audio output bin from GStreamer Hal UDI.
+ * If no device with the specified UDI exists or @udi is NULL,
+ * the default audio sink for the platform is used
+ * (typically alsasink, osssink or sunaudiosink).
+ *
+ * Returns: a #GstElement containing the audio output bin, or NULL if
+ * everything failed.
+ */
+GstElement *
+gst_hal_get_audio_sink (const gchar * udi)
+{
+ GstElement *ret = NULL;
+
+ if (udi)
+ ret = gst_hal_render_bin_from_udi (udi, GST_HAL_AUDIOSINK);
+
+ if (!ret) {
+ ret = gst_element_factory_make (DEFAULT_AUDIOSINK, NULL);
+
+ if (!ret)
+ GST_ERROR ("Hal audio sink and %s don't work", DEFAULT_AUDIOSINK);
+ }
+
+ return ret;
+}
+
+/**
+ * gst_hal_get_audio_src:
+ * @udi: a #gchar string corresponding to a Hal UDI.
+ *
+ * Render audio acquisition bin from GStreamer Hal UDI.
+ * If no device with the specified UDI exists or @udi is NULL,
+ * the default audio source for the plaform is used
+ * (typically alsasrc, osssrc or sunaudiosrc).
+ *
+ * Returns: a #GstElement containing the audio source bin, or NULL if
+ * everything failed.
+ */
+GstElement *
+gst_hal_get_audio_src (const gchar * udi)
+{
+ GstElement *ret = NULL;
+
+ if (udi)
+ ret = gst_hal_render_bin_from_udi (udi, GST_HAL_AUDIOSRC);
+
+ if (!ret) {
+ ret = gst_element_factory_make (DEFAULT_AUDIOSRC, NULL);
+
+ if (!ret)
+ GST_ERROR ("Hal audio src and %s don't work", DEFAULT_AUDIOSRC);
+ }
+
+ return ret;
+}
diff --git a/ext/hal/hal.h b/ext/hal/hal.h
new file mode 100644
index 0000000..9cc5aed
--- /dev/null
+++ b/ext/hal/hal.h
@@ -0,0 +1,48 @@
+/* GStreamer
+ * Copyright (C) <2002> Thomas Vander Stichele <thomas@apestaart.org>
+ * Copyright (C) <2006> Jürg Billeter <j@bitron.ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GST_HAL_H
+#define GST_HAL_H
+
+/*
+ * this library handles interaction with Hal
+ */
+
+#include <gst/gst.h>
+#include <dbus/dbus.h>
+#include <libhal.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ GST_HAL_AUDIOSINK,
+ GST_HAL_AUDIOSRC
+} GstHalDeviceType;
+
+GstElement *gst_hal_render_bin_from_udi (const gchar * udi,
+ GstHalDeviceType type);
+
+GstElement *gst_hal_get_audio_sink (const gchar * udi);
+GstElement *gst_hal_get_audio_src (const gchar * udi);
+
+G_END_DECLS
+
+#endif /* GST_HAL_H */
diff --git a/ext/jack/Makefile.am b/ext/jack/Makefile.am
new file mode 100644
index 0000000..cf77899
--- /dev/null
+++ b/ext/jack/Makefile.am
@@ -0,0 +1,10 @@
+
+plugin_LTLIBRARIES = libgstjack.la
+
+libgstjack_la_SOURCES = gstjackutil.c gstjack.c gstjackaudiosrc.c gstjackaudiosink.c gstjackaudioclient.c
+libgstjack_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(JACK_CFLAGS)
+libgstjack_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(JACK_LIBS)
+libgstjack_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstjack_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstjackutil.h gstjackaudiosrc.h gstjackaudiosink.h gstjackaudioclient.h gstjack.h gstjackringbuffer.h
diff --git a/ext/jack/Makefile.in b/ext/jack/Makefile.in
new file mode 100644
index 0000000..5c4f09f
--- /dev/null
+++ b/ext/jack/Makefile.in
@@ -0,0 +1,840 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/jack
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstjack_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgstjack_la_OBJECTS = libgstjack_la-gstjackutil.lo \
+ libgstjack_la-gstjack.lo libgstjack_la-gstjackaudiosrc.lo \
+ libgstjack_la-gstjackaudiosink.lo \
+ libgstjack_la-gstjackaudioclient.lo
+libgstjack_la_OBJECTS = $(am_libgstjack_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstjack_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstjack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstjack_la_CFLAGS) $(CFLAGS) \
+ $(libgstjack_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstjack_la_SOURCES)
+DIST_SOURCES = $(libgstjack_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstjack.la
+libgstjack_la_SOURCES = gstjackutil.c gstjack.c gstjackaudiosrc.c gstjackaudiosink.c gstjackaudioclient.c
+libgstjack_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(JACK_CFLAGS)
+libgstjack_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(JACK_LIBS)
+libgstjack_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstjack_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = gstjackutil.h gstjackaudiosrc.h gstjackaudiosink.h gstjackaudioclient.h gstjack.h gstjackringbuffer.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/jack/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/jack/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstjack.la: $(libgstjack_la_OBJECTS) $(libgstjack_la_DEPENDENCIES) $(EXTRA_libgstjack_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstjack_la_LINK) -rpath $(plugindir) $(libgstjack_la_OBJECTS) $(libgstjack_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstjack_la-gstjack.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstjack_la-gstjackaudioclient.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstjack_la-gstjackaudiosink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstjack_la-gstjackaudiosrc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstjack_la-gstjackutil.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstjack_la-gstjackutil.lo: gstjackutil.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjack_la_CFLAGS) $(CFLAGS) -MT libgstjack_la-gstjackutil.lo -MD -MP -MF $(DEPDIR)/libgstjack_la-gstjackutil.Tpo -c -o libgstjack_la-gstjackutil.lo `test -f 'gstjackutil.c' || echo '$(srcdir)/'`gstjackutil.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstjack_la-gstjackutil.Tpo $(DEPDIR)/libgstjack_la-gstjackutil.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstjackutil.c' object='libgstjack_la-gstjackutil.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjack_la_CFLAGS) $(CFLAGS) -c -o libgstjack_la-gstjackutil.lo `test -f 'gstjackutil.c' || echo '$(srcdir)/'`gstjackutil.c
+
+libgstjack_la-gstjack.lo: gstjack.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjack_la_CFLAGS) $(CFLAGS) -MT libgstjack_la-gstjack.lo -MD -MP -MF $(DEPDIR)/libgstjack_la-gstjack.Tpo -c -o libgstjack_la-gstjack.lo `test -f 'gstjack.c' || echo '$(srcdir)/'`gstjack.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstjack_la-gstjack.Tpo $(DEPDIR)/libgstjack_la-gstjack.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstjack.c' object='libgstjack_la-gstjack.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjack_la_CFLAGS) $(CFLAGS) -c -o libgstjack_la-gstjack.lo `test -f 'gstjack.c' || echo '$(srcdir)/'`gstjack.c
+
+libgstjack_la-gstjackaudiosrc.lo: gstjackaudiosrc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjack_la_CFLAGS) $(CFLAGS) -MT libgstjack_la-gstjackaudiosrc.lo -MD -MP -MF $(DEPDIR)/libgstjack_la-gstjackaudiosrc.Tpo -c -o libgstjack_la-gstjackaudiosrc.lo `test -f 'gstjackaudiosrc.c' || echo '$(srcdir)/'`gstjackaudiosrc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstjack_la-gstjackaudiosrc.Tpo $(DEPDIR)/libgstjack_la-gstjackaudiosrc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstjackaudiosrc.c' object='libgstjack_la-gstjackaudiosrc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjack_la_CFLAGS) $(CFLAGS) -c -o libgstjack_la-gstjackaudiosrc.lo `test -f 'gstjackaudiosrc.c' || echo '$(srcdir)/'`gstjackaudiosrc.c
+
+libgstjack_la-gstjackaudiosink.lo: gstjackaudiosink.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjack_la_CFLAGS) $(CFLAGS) -MT libgstjack_la-gstjackaudiosink.lo -MD -MP -MF $(DEPDIR)/libgstjack_la-gstjackaudiosink.Tpo -c -o libgstjack_la-gstjackaudiosink.lo `test -f 'gstjackaudiosink.c' || echo '$(srcdir)/'`gstjackaudiosink.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstjack_la-gstjackaudiosink.Tpo $(DEPDIR)/libgstjack_la-gstjackaudiosink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstjackaudiosink.c' object='libgstjack_la-gstjackaudiosink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjack_la_CFLAGS) $(CFLAGS) -c -o libgstjack_la-gstjackaudiosink.lo `test -f 'gstjackaudiosink.c' || echo '$(srcdir)/'`gstjackaudiosink.c
+
+libgstjack_la-gstjackaudioclient.lo: gstjackaudioclient.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjack_la_CFLAGS) $(CFLAGS) -MT libgstjack_la-gstjackaudioclient.lo -MD -MP -MF $(DEPDIR)/libgstjack_la-gstjackaudioclient.Tpo -c -o libgstjack_la-gstjackaudioclient.lo `test -f 'gstjackaudioclient.c' || echo '$(srcdir)/'`gstjackaudioclient.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstjack_la-gstjackaudioclient.Tpo $(DEPDIR)/libgstjack_la-gstjackaudioclient.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstjackaudioclient.c' object='libgstjack_la-gstjackaudioclient.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjack_la_CFLAGS) $(CFLAGS) -c -o libgstjack_la-gstjackaudioclient.lo `test -f 'gstjackaudioclient.c' || echo '$(srcdir)/'`gstjackaudioclient.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/jack/gstjack.c b/ext/jack/gstjack.c
new file mode 100644
index 0000000..8180afb
--- /dev/null
+++ b/ext/jack/gstjack.c
@@ -0,0 +1,97 @@
+/* GStreamer Jack plugins
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstjackaudiosrc.h"
+#include "gstjackaudiosink.h"
+
+GType
+gst_jack_connect_get_type (void)
+{
+ static volatile gsize jack_connect_type = 0;
+
+ if (g_once_init_enter (&jack_connect_type)) {
+ static const GEnumValue jack_connect_enums[] = {
+ {GST_JACK_CONNECT_NONE,
+ "Don't automatically connect ports to physical ports", "none"},
+ {GST_JACK_CONNECT_AUTO,
+ "Automatically connect ports to physical ports", "auto"},
+ {GST_JACK_CONNECT_AUTO_FORCED,
+ "Automatically connect ports to as many physical ports as possible",
+ "auto-forced"},
+ {0, NULL, NULL},
+ };
+ GType tmp = g_enum_register_static ("GstJackConnect", jack_connect_enums);
+ g_once_init_leave (&jack_connect_type, tmp);
+ }
+ return (GType) jack_connect_type;
+}
+
+
+static gpointer
+gst_jack_client_copy (gpointer jclient)
+{
+ return jclient;
+}
+
+
+static void
+gst_jack_client_free (gpointer jclient)
+{
+ return;
+}
+
+
+GType
+gst_jack_client_get_type (void)
+{
+ static volatile gsize jack_client_type = 0;
+
+ if (g_once_init_enter (&jack_client_type)) {
+ /* hackish, but makes it show up nicely in gst-inspect */
+ GType tmp = g_boxed_type_register_static ("JackClient",
+ (GBoxedCopyFunc) gst_jack_client_copy,
+ (GBoxedFreeFunc) gst_jack_client_free);
+ g_once_init_leave (&jack_client_type, tmp);
+ }
+
+ return (GType) jack_client_type;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "jackaudiosrc", GST_RANK_PRIMARY,
+ GST_TYPE_JACK_AUDIO_SRC))
+ return FALSE;
+ if (!gst_element_register (plugin, "jackaudiosink", GST_RANK_PRIMARY,
+ GST_TYPE_JACK_AUDIO_SINK))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "jack",
+ "JACK audio elements",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/jack/gstjack.h b/ext/jack/gstjack.h
new file mode 100644
index 0000000..d923866
--- /dev/null
+++ b/ext/jack/gstjack.h
@@ -0,0 +1,55 @@
+/* GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * gstjack.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GST_JACK_H_
+#define _GST_JACK_H_
+
+
+/**
+ * GstJackConnect:
+ * @GST_JACK_CONNECT_NONE: Don't automatically connect to physical ports.
+ * In this mode, the element will accept any number of input channels and will
+ * create (but not connect) an output port for each channel.
+ * @GST_JACK_CONNECT_AUTO: In this mode, the element will try to connect each
+ * output port to a random physical jack input pin. The sink will
+ * expose the number of physical channels on its pad caps.
+ * @GST_JACK_CONNECT_AUTO_FORCED: In this mode, the element will try to connect each
+ * output port to a random physical jack input pin. The element will accept any number
+ * of input channels.
+ *
+ * Specify how the output ports will be connected.
+ */
+
+typedef enum {
+ GST_JACK_CONNECT_NONE,
+ GST_JACK_CONNECT_AUTO,
+ GST_JACK_CONNECT_AUTO_FORCED
+} GstJackConnect;
+
+typedef jack_default_audio_sample_t sample_t;
+
+#define GST_TYPE_JACK_CONNECT (gst_jack_connect_get_type())
+#define GST_TYPE_JACK_CLIENT (gst_jack_client_get_type ())
+
+GType gst_jack_client_get_type(void);
+GType gst_jack_connect_get_type(void);
+
+#endif // _GST_JACK_H_
diff --git a/ext/jack/gstjackaudioclient.c b/ext/jack/gstjackaudioclient.c
new file mode 100644
index 0000000..2bb3555
--- /dev/null
+++ b/ext/jack/gstjackaudioclient.c
@@ -0,0 +1,527 @@
+/* GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * gstjackaudioclient.c: jack audio client implementation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "gstjackaudioclient.h"
+
+#include <gst/glib-compat-private.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_jack_audio_client_debug);
+#define GST_CAT_DEFAULT gst_jack_audio_client_debug
+
+void
+gst_jack_audio_client_init (void)
+{
+ GST_DEBUG_CATEGORY_INIT (gst_jack_audio_client_debug, "jackclient", 0,
+ "jackclient helpers");
+}
+
+/* a list of global connections indexed by id and server. */
+G_LOCK_DEFINE_STATIC (connections_lock);
+static GList *connections;
+
+/* the connection to a server */
+typedef struct
+{
+ gint refcount;
+ GMutex *lock;
+ GCond *flush_cond;
+
+ /* id/server pair and the connection */
+ gchar *id;
+ gchar *server;
+ jack_client_t *client;
+
+ /* lists of GstJackAudioClients */
+ gint n_clients;
+ GList *src_clients;
+ GList *sink_clients;
+} GstJackAudioConnection;
+
+/* an object sharing a jack_client_t connection. */
+struct _GstJackAudioClient
+{
+ GstJackAudioConnection *conn;
+
+ GstJackClientType type;
+ gboolean active;
+ gboolean deactivate;
+
+ void (*shutdown) (void *arg);
+ JackProcessCallback process;
+ JackBufferSizeCallback buffer_size;
+ JackSampleRateCallback sample_rate;
+ gpointer user_data;
+};
+
+typedef jack_default_audio_sample_t sample_t;
+
+typedef struct
+{
+ jack_nframes_t nframes;
+ gpointer user_data;
+} JackCB;
+
+static int
+jack_process_cb (jack_nframes_t nframes, void *arg)
+{
+ GstJackAudioConnection *conn = (GstJackAudioConnection *) arg;
+ GList *walk;
+ int res = 0;
+
+ g_mutex_lock (conn->lock);
+ /* call sources first, then sinks. Sources will either push data into the
+ * ringbuffer of the sinks, which will then pull the data out of it, or
+ * sinks will pull the data from the sources. */
+ for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
+ GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
+
+ /* only call active clients */
+ if ((client->active || client->deactivate) && client->process) {
+ res = client->process (nframes, client->user_data);
+ if (client->deactivate) {
+ client->deactivate = FALSE;
+ g_cond_signal (conn->flush_cond);
+ }
+ }
+ }
+ for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
+ GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
+
+ /* only call active clients */
+ if ((client->active || client->deactivate) && client->process) {
+ res = client->process (nframes, client->user_data);
+ if (client->deactivate) {
+ client->deactivate = FALSE;
+ g_cond_signal (conn->flush_cond);
+ }
+ }
+ }
+ g_mutex_unlock (conn->lock);
+
+ return res;
+}
+
+/* we error out */
+static int
+jack_sample_rate_cb (jack_nframes_t nframes, void *arg)
+{
+ return 0;
+}
+
+/* we error out */
+static int
+jack_buffer_size_cb (jack_nframes_t nframes, void *arg)
+{
+ return 0;
+}
+
+static void
+jack_shutdown_cb (void *arg)
+{
+ GstJackAudioConnection *conn = (GstJackAudioConnection *) arg;
+ GList *walk;
+
+ GST_DEBUG ("disconnect client %s from server %s", conn->id,
+ GST_STR_NULL (conn->server));
+
+ g_mutex_lock (conn->lock);
+ for (walk = conn->src_clients; walk; walk = g_list_next (walk)) {
+ GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
+
+ if (client->shutdown)
+ client->shutdown (client->user_data);
+ }
+ for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
+ GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
+
+ if (client->shutdown)
+ client->shutdown (client->user_data);
+ }
+ g_mutex_unlock (conn->lock);
+}
+
+typedef struct
+{
+ const gchar *id;
+ const gchar *server;
+} FindData;
+
+static gint
+connection_find (GstJackAudioConnection * conn, FindData * data)
+{
+ /* id's must match */
+ if (strcmp (conn->id, data->id))
+ return 1;
+
+ /* both the same or NULL */
+ if (conn->server == data->server)
+ return 0;
+
+ /* we cannot compare NULL */
+ if (conn->server == NULL || data->server == NULL)
+ return 1;
+
+ if (strcmp (conn->server, data->server))
+ return 1;
+
+ return 0;
+}
+
+/* make a connection with @id and @server. Returns NULL on failure with the
+ * status set. */
+static GstJackAudioConnection *
+gst_jack_audio_make_connection (const gchar * id, const gchar * server,
+ jack_client_t * jclient, jack_status_t * status)
+{
+ GstJackAudioConnection *conn;
+ jack_options_t options;
+ gint res;
+
+ *status = 0;
+
+ GST_DEBUG ("new client %s, connecting to server %s", id,
+ GST_STR_NULL (server));
+
+ /* never start a server */
+ options = JackNoStartServer;
+ /* if we have a servername, use it */
+ if (server != NULL)
+ options |= JackServerName;
+ /* open the client */
+ if (jclient == NULL)
+ jclient = jack_client_open (id, options, status, server);
+ if (jclient == NULL)
+ goto could_not_open;
+
+ /* now create object */
+ conn = g_new (GstJackAudioConnection, 1);
+ conn->refcount = 1;
+ conn->lock = g_mutex_new ();
+ conn->flush_cond = g_cond_new ();
+ conn->id = g_strdup (id);
+ conn->server = g_strdup (server);
+ conn->client = jclient;
+ conn->n_clients = 0;
+ conn->src_clients = NULL;
+ conn->sink_clients = NULL;
+
+ /* set our callbacks */
+ jack_set_process_callback (jclient, jack_process_cb, conn);
+ /* these callbacks cause us to error */
+ jack_set_buffer_size_callback (jclient, jack_buffer_size_cb, conn);
+ jack_set_sample_rate_callback (jclient, jack_sample_rate_cb, conn);
+ jack_on_shutdown (jclient, jack_shutdown_cb, conn);
+
+ /* all callbacks are set, activate the client */
+ if ((res = jack_activate (jclient)))
+ goto could_not_activate;
+
+ GST_DEBUG ("opened connection %p", conn);
+
+ return conn;
+
+ /* ERRORS */
+could_not_open:
+ {
+ GST_DEBUG ("failed to open jack client, %d", *status);
+ return NULL;
+ }
+could_not_activate:
+ {
+ GST_ERROR ("Could not activate client (%d)", res);
+ *status = JackFailure;
+ g_mutex_free (conn->lock);
+ g_free (conn->id);
+ g_free (conn->server);
+ g_free (conn);
+ return NULL;
+ }
+}
+
+static GstJackAudioConnection *
+gst_jack_audio_get_connection (const gchar * id, const gchar * server,
+ jack_client_t * jclient, jack_status_t * status)
+{
+ GstJackAudioConnection *conn;
+ GList *found;
+ FindData data;
+
+ GST_DEBUG ("getting connection for id %s, server %s", id,
+ GST_STR_NULL (server));
+
+ data.id = id;
+ data.server = server;
+
+ G_LOCK (connections_lock);
+ found =
+ g_list_find_custom (connections, &data, (GCompareFunc) connection_find);
+ if (found != NULL && jclient != NULL) {
+ /* we found it, increase refcount and return it */
+ conn = (GstJackAudioConnection *) found->data;
+ conn->refcount++;
+
+ GST_DEBUG ("found connection %p", conn);
+ } else {
+ /* make new connection */
+ conn = gst_jack_audio_make_connection (id, server, jclient, status);
+ if (conn != NULL) {
+ GST_DEBUG ("created connection %p", conn);
+ /* add to list on success */
+ connections = g_list_prepend (connections, conn);
+ } else {
+ GST_WARNING ("could not create connection");
+ }
+ }
+ G_UNLOCK (connections_lock);
+
+ return conn;
+}
+
+static void
+gst_jack_audio_unref_connection (GstJackAudioConnection * conn)
+{
+ gint res;
+ gboolean zero;
+
+ GST_DEBUG ("unref connection %p refcnt %d", conn, conn->refcount);
+
+ G_LOCK (connections_lock);
+ conn->refcount--;
+ if ((zero = (conn->refcount == 0))) {
+ GST_DEBUG ("closing connection %p", conn);
+ /* remove from list, we can release the mutex after removing the connection
+ * from the list because after that, nobody can access the connection anymore. */
+ connections = g_list_remove (connections, conn);
+ }
+ G_UNLOCK (connections_lock);
+
+ /* if we are zero, close and cleanup the connection */
+ if (zero) {
+ /* don't use conn->lock here. two reasons:
+ *
+ * 1) its not necessary: jack_deactivate() will not return until the JACK thread
+ * associated with this connection is cleaned up by a thread join, hence
+ * no more callbacks can occur or be in progress.
+ *
+ * 2) it would deadlock anyway, because jack_deactivate() will sleep
+ * waiting for the JACK thread, and can thus cause deadlock in
+ * jack_process_cb()
+ */
+ if ((res = jack_deactivate (conn->client))) {
+ /* we only warn, this means the server is probably shut down and the client
+ * is gone anyway. */
+ GST_WARNING ("Could not deactivate Jack client (%d)", res);
+ }
+ /* close connection */
+ if ((res = jack_client_close (conn->client))) {
+ /* we assume the client is gone. */
+ GST_WARNING ("close failed (%d)", res);
+ }
+
+ /* free resources */
+ g_mutex_free (conn->lock);
+ g_cond_free (conn->flush_cond);
+ g_free (conn->id);
+ g_free (conn->server);
+ g_free (conn);
+ }
+}
+
+static void
+gst_jack_audio_connection_add_client (GstJackAudioConnection * conn,
+ GstJackAudioClient * client)
+{
+ g_mutex_lock (conn->lock);
+ switch (client->type) {
+ case GST_JACK_CLIENT_SOURCE:
+ conn->src_clients = g_list_append (conn->src_clients, client);
+ conn->n_clients++;
+ break;
+ case GST_JACK_CLIENT_SINK:
+ conn->sink_clients = g_list_append (conn->sink_clients, client);
+ conn->n_clients++;
+ break;
+ default:
+ g_warning ("trying to add unknown client type");
+ break;
+ }
+ g_mutex_unlock (conn->lock);
+}
+
+static void
+gst_jack_audio_connection_remove_client (GstJackAudioConnection * conn,
+ GstJackAudioClient * client)
+{
+ g_mutex_lock (conn->lock);
+ switch (client->type) {
+ case GST_JACK_CLIENT_SOURCE:
+ conn->src_clients = g_list_remove (conn->src_clients, client);
+ conn->n_clients--;
+ break;
+ case GST_JACK_CLIENT_SINK:
+ conn->sink_clients = g_list_remove (conn->sink_clients, client);
+ conn->n_clients--;
+ break;
+ default:
+ g_warning ("trying to remove unknown client type");
+ break;
+ }
+ g_mutex_unlock (conn->lock);
+}
+
+/**
+ * gst_jack_audio_client_get:
+ * @id: the client id
+ * @server: the server to connect to or NULL for the default server
+ * @type: the client type
+ * @shutdown: a callback when the jack server shuts down
+ * @process: a callback when samples are available
+ * @buffer_size: a callback when the buffer_size changes
+ * @sample_rate: a callback when the sample_rate changes
+ * @user_data: user data passed to the callbacks
+ * @status: pointer to hold the jack status code in case of errors
+ *
+ * Get the jack client connection for @id and @server. Connections to the same
+ * @id and @server will receive the same physical Jack client connection and
+ * will therefore be scheduled in the same process callback.
+ *
+ * Returns: a #GstJackAudioClient.
+ */
+GstJackAudioClient *
+gst_jack_audio_client_new (const gchar * id, const gchar * server,
+ jack_client_t * jclient, GstJackClientType type,
+ void (*shutdown) (void *arg), JackProcessCallback process,
+ JackBufferSizeCallback buffer_size, JackSampleRateCallback sample_rate,
+ gpointer user_data, jack_status_t * status)
+{
+ GstJackAudioClient *client;
+ GstJackAudioConnection *conn;
+
+ g_return_val_if_fail (id != NULL, NULL);
+ g_return_val_if_fail (status != NULL, NULL);
+
+ /* first get a connection for the id/server pair */
+ conn = gst_jack_audio_get_connection (id, server, jclient, status);
+ if (conn == NULL)
+ goto no_connection;
+
+ GST_INFO ("new client %s", id);
+
+ /* make new client using the connection */
+ client = g_new (GstJackAudioClient, 1);
+ client->active = client->deactivate = FALSE;
+ client->conn = conn;
+ client->type = type;
+ client->shutdown = shutdown;
+ client->process = process;
+ client->buffer_size = buffer_size;
+ client->sample_rate = sample_rate;
+ client->user_data = user_data;
+
+ /* add the client to the connection */
+ gst_jack_audio_connection_add_client (conn, client);
+
+ return client;
+
+ /* ERRORS */
+no_connection:
+ {
+ GST_DEBUG ("Could not get server connection (%d)", *status);
+ return NULL;
+ }
+}
+
+/**
+ * gst_jack_audio_client_free:
+ * @client: a #GstJackAudioClient
+ *
+ * Free the resources used by @client.
+ */
+void
+gst_jack_audio_client_free (GstJackAudioClient * client)
+{
+ GstJackAudioConnection *conn;
+
+ g_return_if_fail (client != NULL);
+
+ GST_INFO ("free client");
+
+ conn = client->conn;
+
+ /* remove from connection first so that it's not scheduled anymore after this
+ * call */
+ gst_jack_audio_connection_remove_client (conn, client);
+ gst_jack_audio_unref_connection (conn);
+
+ g_free (client);
+}
+
+/**
+ * gst_jack_audio_client_get_client:
+ * @client: a #GstJackAudioClient
+ *
+ * Get the jack audio client for @client. This function is used to perform
+ * operations on the jack server from this client.
+ *
+ * Returns: The jack audio client.
+ */
+jack_client_t *
+gst_jack_audio_client_get_client (GstJackAudioClient * client)
+{
+ g_return_val_if_fail (client != NULL, NULL);
+
+ /* no lock needed, the connection and the client does not change
+ * once the client is created. */
+ return client->conn->client;
+}
+
+/**
+ * gst_jack_audio_client_set_active:
+ * @client: a #GstJackAudioClient
+ * @active: new mode for the client
+ *
+ * Activate or deactive @client. When a client is activated it will receive
+ * callbacks when data should be processed.
+ *
+ * Returns: 0 if all ok.
+ */
+gint
+gst_jack_audio_client_set_active (GstJackAudioClient * client, gboolean active)
+{
+ g_return_val_if_fail (client != NULL, -1);
+
+ /* make sure that we are not dispatching the client */
+ g_mutex_lock (client->conn->lock);
+ if (client->active && !active) {
+ /* we need to process once more to flush the port */
+ client->deactivate = TRUE;
+
+ /* need to wait for process_cb run once more */
+ while (client->deactivate)
+ g_cond_wait (client->conn->flush_cond, client->conn->lock);
+ }
+ client->active = active;
+ g_mutex_unlock (client->conn->lock);
+
+ return 0;
+}
diff --git a/ext/jack/gstjackaudioclient.h b/ext/jack/gstjackaudioclient.h
new file mode 100644
index 0000000..5fb7e35
--- /dev/null
+++ b/ext/jack/gstjackaudioclient.h
@@ -0,0 +1,59 @@
+/* GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * gstjackaudioclient.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_JACK_AUDIO_CLIENT_H__
+#define __GST_JACK_AUDIO_CLIENT_H__
+
+#include <jack/jack.h>
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ GST_JACK_CLIENT_SOURCE,
+ GST_JACK_CLIENT_SINK
+} GstJackClientType;
+
+typedef struct _GstJackAudioClient GstJackAudioClient;
+
+void gst_jack_audio_client_init (void);
+
+
+GstJackAudioClient * gst_jack_audio_client_new (const gchar *id, const gchar *server,
+ jack_client_t *jclient,
+ GstJackClientType type,
+ void (*shutdown) (void *arg),
+ JackProcessCallback process,
+ JackBufferSizeCallback buffer_size,
+ JackSampleRateCallback sample_rate,
+ gpointer user_data,
+ jack_status_t *status);
+void gst_jack_audio_client_free (GstJackAudioClient *client);
+
+jack_client_t * gst_jack_audio_client_get_client (GstJackAudioClient *client);
+
+gboolean gst_jack_audio_client_set_active (GstJackAudioClient *client, gboolean active);
+
+G_END_DECLS
+
+#endif /* __GST_JACK_AUDIO_CLIENT_H__ */
diff --git a/ext/jack/gstjackaudiosink.c b/ext/jack/gstjackaudiosink.c
new file mode 100644
index 0000000..078ca24
--- /dev/null
+++ b/ext/jack/gstjackaudiosink.c
@@ -0,0 +1,903 @@
+/* GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * gstjackaudiosink.c: jack audio sink implementation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-jackaudiosink
+ * @see_also: #GstBaseAudioSink, #GstRingBuffer
+ *
+ * A Sink that outputs data to Jack ports.
+ *
+ * It will create N Jack ports named out_&lt;name&gt;_&lt;num&gt; where
+ * &lt;name&gt; is the element name and &lt;num&gt; is starting from 1.
+ * Each port corresponds to a gstreamer channel.
+ *
+ * The samplerate as exposed on the caps is always the same as the samplerate of
+ * the jack server.
+ *
+ * When the #GstJackAudioSink:connect property is set to auto, this element
+ * will try to connect each output port to a random physical jack input pin. In
+ * this mode, the sink will expose the number of physical channels on its pad
+ * caps.
+ *
+ * When the #GstJackAudioSink:connect property is set to none, the element will
+ * accept any number of input channels and will create (but not connect) an
+ * output port for each channel.
+ *
+ * The element will generate an error when the Jack server is shut down when it
+ * was PAUSED or PLAYING. This element does not support dynamic rate and buffer
+ * size changes at runtime.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch audiotestsrc ! jackaudiosink
+ * ]| Play a sine wave to using jack.
+ * </refsect2>
+ *
+ * Last reviewed on 2006-11-30 (0.10.4)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst-i18n-plugin.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gstjackaudiosink.h"
+#include "gstjackringbuffer.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_jack_audio_sink_debug);
+#define GST_CAT_DEFAULT gst_jack_audio_sink_debug
+
+static gboolean
+gst_jack_audio_sink_allocate_channels (GstJackAudioSink * sink, gint channels)
+{
+ jack_client_t *client;
+
+ client = gst_jack_audio_client_get_client (sink->client);
+
+ /* remove ports we don't need */
+ while (sink->port_count > channels) {
+ jack_port_unregister (client, sink->ports[--sink->port_count]);
+ }
+
+ /* alloc enough output ports */
+ sink->ports = g_realloc (sink->ports, sizeof (jack_port_t *) * channels);
+ sink->buffers = g_realloc (sink->buffers, sizeof (sample_t *) * channels);
+
+ /* create an output port for each channel */
+ while (sink->port_count < channels) {
+ gchar *name;
+
+ /* port names start from 1 and are local to the element */
+ name =
+ g_strdup_printf ("out_%s_%d", GST_ELEMENT_NAME (sink),
+ sink->port_count + 1);
+ sink->ports[sink->port_count] =
+ jack_port_register (client, name, JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
+ if (sink->ports[sink->port_count] == NULL)
+ return FALSE;
+
+ sink->port_count++;
+
+ g_free (name);
+ }
+ return TRUE;
+}
+
+static void
+gst_jack_audio_sink_free_channels (GstJackAudioSink * sink)
+{
+ gint res, i = 0;
+ jack_client_t *client;
+
+ client = gst_jack_audio_client_get_client (sink->client);
+
+ /* get rid of all ports */
+ while (sink->port_count) {
+ GST_LOG_OBJECT (sink, "unregister port %d", i);
+ if ((res = jack_port_unregister (client, sink->ports[i++]))) {
+ GST_DEBUG_OBJECT (sink, "unregister of port failed (%d)", res);
+ }
+ sink->port_count--;
+ }
+ g_free (sink->ports);
+ sink->ports = NULL;
+ g_free (sink->buffers);
+ sink->buffers = NULL;
+}
+
+/* ringbuffer abstract base class */
+static GType
+gst_jack_ring_buffer_get_type (void)
+{
+ static volatile gsize ringbuffer_type = 0;
+
+ if (g_once_init_enter (&ringbuffer_type)) {
+ static const GTypeInfo ringbuffer_info = {
+ sizeof (GstJackRingBufferClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gst_jack_ring_buffer_class_init,
+ NULL,
+ NULL,
+ sizeof (GstJackRingBuffer),
+ 0,
+ (GInstanceInitFunc) gst_jack_ring_buffer_init,
+ NULL
+ };
+ GType tmp = g_type_register_static (GST_TYPE_RING_BUFFER,
+ "GstJackAudioSinkRingBuffer", &ringbuffer_info, 0);
+ g_once_init_leave (&ringbuffer_type, tmp);
+ }
+
+ return (GType) ringbuffer_type;
+}
+
+static void
+gst_jack_ring_buffer_class_init (GstJackRingBufferClass * klass)
+{
+ GstRingBufferClass *gstringbuffer_class;
+
+ gstringbuffer_class = (GstRingBufferClass *) klass;
+
+ ring_parent_class = g_type_class_peek_parent (klass);
+
+ gstringbuffer_class->open_device =
+ GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_open_device);
+ gstringbuffer_class->close_device =
+ GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_close_device);
+ gstringbuffer_class->acquire =
+ GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_acquire);
+ gstringbuffer_class->release =
+ GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_release);
+ gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_start);
+ gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_pause);
+ gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_start);
+ gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_stop);
+
+ gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_delay);
+}
+
+/* this is the callback of jack. This should RT-safe.
+ */
+static int
+jack_process_cb (jack_nframes_t nframes, void *arg)
+{
+ GstJackAudioSink *sink;
+ GstRingBuffer *buf;
+ gint readseg, len;
+ guint8 *readptr;
+ gint i, j, flen, channels;
+ sample_t *data;
+
+ buf = GST_RING_BUFFER_CAST (arg);
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+ channels = buf->spec.channels;
+
+ /* get target buffers */
+ for (i = 0; i < channels; i++) {
+ sink->buffers[i] =
+ (sample_t *) jack_port_get_buffer (sink->ports[i], nframes);
+ }
+
+ if (gst_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
+ flen = len / channels;
+
+ /* the number of samples must be exactly the segment size */
+ if (nframes * sizeof (sample_t) != flen)
+ goto wrong_size;
+
+ GST_DEBUG_OBJECT (sink, "copy %d frames: %p, %d bytes, %d channels",
+ nframes, readptr, flen, channels);
+ data = (sample_t *) readptr;
+
+ /* the samples in the ringbuffer have the channels interleaved, we need to
+ * deinterleave into the jack target buffers */
+ for (i = 0; i < nframes; i++) {
+ for (j = 0; j < channels; j++) {
+ sink->buffers[j][i] = *data++;
+ }
+ }
+
+ /* clear written samples in the ringbuffer */
+ gst_ring_buffer_clear (buf, readseg);
+
+ /* we wrote one segment */
+ gst_ring_buffer_advance (buf, 1);
+ } else {
+ GST_DEBUG_OBJECT (sink, "write %d frames silence", nframes);
+ /* We are not allowed to read from the ringbuffer, write silence to all
+ * jack output buffers */
+ for (i = 0; i < channels; i++) {
+ memset (sink->buffers[i], 0, nframes * sizeof (sample_t));
+ }
+ }
+ return 0;
+
+ /* ERRORS */
+wrong_size:
+ {
+ GST_ERROR_OBJECT (sink, "nbytes (%d) != flen (%d)",
+ (gint) (nframes * sizeof (sample_t)), flen);
+ return 1;
+ }
+}
+
+/* we error out */
+static int
+jack_sample_rate_cb (jack_nframes_t nframes, void *arg)
+{
+ GstJackAudioSink *sink;
+ GstJackRingBuffer *abuf;
+
+ abuf = GST_JACK_RING_BUFFER_CAST (arg);
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (arg));
+
+ if (abuf->sample_rate != -1 && abuf->sample_rate != nframes)
+ goto not_supported;
+
+ return 0;
+
+ /* ERRORS */
+not_supported:
+ {
+ GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS,
+ (NULL), ("Jack changed the sample rate, which is not supported"));
+ return 1;
+ }
+}
+
+/* we error out */
+static int
+jack_buffer_size_cb (jack_nframes_t nframes, void *arg)
+{
+ GstJackAudioSink *sink;
+ GstJackRingBuffer *abuf;
+
+ abuf = GST_JACK_RING_BUFFER_CAST (arg);
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (arg));
+
+ if (abuf->buffer_size != -1 && abuf->buffer_size != nframes)
+ goto not_supported;
+
+ return 0;
+
+ /* ERRORS */
+not_supported:
+ {
+ GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS,
+ (NULL), ("Jack changed the buffer size, which is not supported"));
+ return 1;
+ }
+}
+
+static void
+jack_shutdown_cb (void *arg)
+{
+ GstJackAudioSink *sink;
+
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (arg));
+
+ GST_DEBUG_OBJECT (sink, "shutdown");
+
+ GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
+ (NULL), ("Jack server shutdown"));
+}
+
+static void
+gst_jack_ring_buffer_init (GstJackRingBuffer * buf,
+ GstJackRingBufferClass * g_class)
+{
+ buf->channels = -1;
+ buf->buffer_size = -1;
+ buf->sample_rate = -1;
+}
+
+/* the _open_device method should make a connection with the server
+ */
+static gboolean
+gst_jack_ring_buffer_open_device (GstRingBuffer * buf)
+{
+ GstJackAudioSink *sink;
+ jack_status_t status = 0;
+ const gchar *name;
+
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+ GST_DEBUG_OBJECT (sink, "open");
+
+ if (sink->client_name) {
+ name = sink->client_name;
+ } else {
+ name = g_get_application_name ();
+ }
+ if (!name)
+ name = "GStreamer";
+
+ sink->client = gst_jack_audio_client_new (name, sink->server,
+ sink->jclient,
+ GST_JACK_CLIENT_SINK,
+ jack_shutdown_cb,
+ jack_process_cb, jack_buffer_size_cb, jack_sample_rate_cb, buf, &status);
+ if (sink->client == NULL)
+ goto could_not_open;
+
+ GST_DEBUG_OBJECT (sink, "opened");
+
+ return TRUE;
+
+ /* ERRORS */
+could_not_open:
+ {
+ if (status & JackServerFailed) {
+ GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
+ (_("Jack server not found")),
+ ("Cannot connect to the Jack server (status %d)", status));
+ } else {
+ GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
+ (NULL), ("Jack client open error (status %d)", status));
+ }
+ return FALSE;
+ }
+}
+
+/* close the connection with the server
+ */
+static gboolean
+gst_jack_ring_buffer_close_device (GstRingBuffer * buf)
+{
+ GstJackAudioSink *sink;
+
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+ GST_DEBUG_OBJECT (sink, "close");
+
+ gst_jack_audio_sink_free_channels (sink);
+ gst_jack_audio_client_free (sink->client);
+ sink->client = NULL;
+
+ return TRUE;
+}
+
+/* allocate a buffer and setup resources to process the audio samples of
+ * the format as specified in @spec.
+ *
+ * We allocate N jack ports, one for each channel. If we are asked to
+ * automatically make a connection with physical ports, we connect as many
+ * ports as there are physical ports, leaving leftover ports unconnected.
+ *
+ * It is assumed that samplerate and number of channels are acceptable since our
+ * getcaps method will always provide correct values. If unacceptable caps are
+ * received for some reason, we fail here.
+ */
+static gboolean
+gst_jack_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
+{
+ GstJackAudioSink *sink;
+ GstJackRingBuffer *abuf;
+ const char **ports;
+ gint sample_rate, buffer_size;
+ gint i, channels, res;
+ jack_client_t *client;
+
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+ abuf = GST_JACK_RING_BUFFER_CAST (buf);
+
+ GST_DEBUG_OBJECT (sink, "acquire");
+
+ client = gst_jack_audio_client_get_client (sink->client);
+
+ /* sample rate must be that of the server */
+ sample_rate = jack_get_sample_rate (client);
+ if (sample_rate != spec->rate)
+ goto wrong_samplerate;
+
+ channels = spec->channels;
+
+ if (!gst_jack_audio_sink_allocate_channels (sink, channels))
+ goto out_of_ports;
+
+ buffer_size = jack_get_buffer_size (client);
+
+ /* the segment size in bytes, this is large enough to hold a buffer of 32bit floats
+ * for all channels */
+ spec->segsize = buffer_size * sizeof (gfloat) * channels;
+ spec->latency_time = gst_util_uint64_scale (spec->segsize,
+ (GST_SECOND / GST_USECOND), spec->rate * spec->bytes_per_sample);
+ /* segtotal based on buffer-time latency */
+ spec->segtotal = spec->buffer_time / spec->latency_time;
+ if (spec->segtotal < 2) {
+ spec->segtotal = 2;
+ spec->buffer_time = spec->latency_time * spec->segtotal;
+ }
+
+ GST_DEBUG_OBJECT (sink, "buffer time: %" G_GINT64_FORMAT " usec",
+ spec->buffer_time);
+ GST_DEBUG_OBJECT (sink, "latency time: %" G_GINT64_FORMAT " usec",
+ spec->latency_time);
+ GST_DEBUG_OBJECT (sink, "buffer_size %d, segsize %d, segtotal %d",
+ buffer_size, spec->segsize, spec->segtotal);
+
+ /* allocate the ringbuffer memory now */
+ buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
+ memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
+
+ if ((res = gst_jack_audio_client_set_active (sink->client, TRUE)))
+ goto could_not_activate;
+
+ /* if we need to automatically connect the ports, do so now. We must do this
+ * after activating the client. */
+ if (sink->connect == GST_JACK_CONNECT_AUTO
+ || sink->connect == GST_JACK_CONNECT_AUTO_FORCED) {
+ /* find all the physical input ports. A physical input port is a port
+ * associated with a hardware device. Someone needs connect to a physical
+ * port in order to hear something. */
+ ports = jack_get_ports (client, NULL, NULL,
+ JackPortIsPhysical | JackPortIsInput);
+ if (ports == NULL) {
+ /* no ports? fine then we don't do anything except for posting a warning
+ * message. */
+ GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND, (NULL),
+ ("No physical input ports found, leaving ports unconnected"));
+ goto done;
+ }
+
+ for (i = 0; i < channels; i++) {
+ /* stop when all input ports are exhausted */
+ if (ports[i] == NULL) {
+ /* post a warning that we could not connect all ports */
+ GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND, (NULL),
+ ("No more physical ports, leaving some ports unconnected"));
+ break;
+ }
+ GST_DEBUG_OBJECT (sink, "try connecting to %s",
+ jack_port_name (sink->ports[i]));
+ /* connect the port to a physical port */
+ res = jack_connect (client, jack_port_name (sink->ports[i]), ports[i]);
+ if (res != 0 && res != EEXIST)
+ goto cannot_connect;
+ }
+ free (ports);
+ }
+done:
+
+ abuf->sample_rate = sample_rate;
+ abuf->buffer_size = buffer_size;
+ abuf->channels = spec->channels;
+
+ return TRUE;
+
+ /* ERRORS */
+wrong_samplerate:
+ {
+ GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+ ("Wrong samplerate, server is running at %d and we received %d",
+ sample_rate, spec->rate));
+ return FALSE;
+ }
+out_of_ports:
+ {
+ GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+ ("Cannot allocate more Jack ports"));
+ return FALSE;
+ }
+could_not_activate:
+ {
+ GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+ ("Could not activate client (%d:%s)", res, g_strerror (res)));
+ return FALSE;
+ }
+cannot_connect:
+ {
+ GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
+ ("Could not connect output ports to physical ports (%d:%s)",
+ res, g_strerror (res)));
+ free (ports);
+ return FALSE;
+ }
+}
+
+/* function is called with LOCK */
+static gboolean
+gst_jack_ring_buffer_release (GstRingBuffer * buf)
+{
+ GstJackAudioSink *sink;
+ GstJackRingBuffer *abuf;
+ gint res;
+
+ abuf = GST_JACK_RING_BUFFER_CAST (buf);
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+ GST_DEBUG_OBJECT (sink, "release");
+
+ if ((res = gst_jack_audio_client_set_active (sink->client, FALSE))) {
+ /* we only warn, this means the server is probably shut down and the client
+ * is gone anyway. */
+ GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL),
+ ("Could not deactivate Jack client (%d)", res));
+ }
+
+ abuf->channels = -1;
+ abuf->buffer_size = -1;
+ abuf->sample_rate = -1;
+
+ /* free the buffer */
+ gst_buffer_unref (buf->data);
+ buf->data = NULL;
+
+ return TRUE;
+}
+
+static gboolean
+gst_jack_ring_buffer_start (GstRingBuffer * buf)
+{
+ GstJackAudioSink *sink;
+
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+ GST_DEBUG_OBJECT (sink, "start");
+
+ return TRUE;
+}
+
+static gboolean
+gst_jack_ring_buffer_pause (GstRingBuffer * buf)
+{
+ GstJackAudioSink *sink;
+
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+ GST_DEBUG_OBJECT (sink, "pause");
+
+ return TRUE;
+}
+
+static gboolean
+gst_jack_ring_buffer_stop (GstRingBuffer * buf)
+{
+ GstJackAudioSink *sink;
+
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+ GST_DEBUG_OBJECT (sink, "stop");
+
+ return TRUE;
+}
+
+#if defined (HAVE_JACK_0_120_1) || defined(HAVE_JACK_1_9_7)
+static guint
+gst_jack_ring_buffer_delay (GstRingBuffer * buf)
+{
+ GstJackAudioSink *sink;
+ guint i, res = 0;
+ jack_latency_range_t range;
+
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+ for (i = 0; i < sink->port_count; i++) {
+ jack_port_get_latency_range (sink->ports[i], JackPlaybackLatency, &range);
+ if (range.max > res)
+ res = range.max;
+ }
+
+ GST_LOG_OBJECT (sink, "delay %u", res);
+
+ return res;
+}
+#else /* !(defined (HAVE_JACK_0_120_1) || defined(HAVE_JACK_1_9_7)) */
+static guint
+gst_jack_ring_buffer_delay (GstRingBuffer * buf)
+{
+ GstJackAudioSink *sink;
+ guint i, res = 0;
+ guint latency;
+ jack_client_t *client;
+
+ sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+ client = gst_jack_audio_client_get_client (sink->client);
+
+ for (i = 0; i < sink->port_count; i++) {
+ latency = jack_port_get_total_latency (client, sink->ports[i]);
+ if (latency > res)
+ res = latency;
+ }
+
+ GST_LOG_OBJECT (sink, "delay %u", res);
+
+ return res;
+}
+#endif
+
+static GstStaticPadTemplate jackaudiosink_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw-float, "
+ "endianness = (int) BYTE_ORDER, "
+ "width = (int) 32, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+ );
+
+/* AudioSink signals and args */
+enum
+{
+ /* FILL ME */
+ SIGNAL_LAST
+};
+
+#define DEFAULT_PROP_CONNECT GST_JACK_CONNECT_AUTO
+#define DEFAULT_PROP_SERVER NULL
+#define DEFAULT_PROP_CLIENT_NAME NULL
+
+enum
+{
+ PROP_0,
+ PROP_CONNECT,
+ PROP_SERVER,
+ PROP_CLIENT,
+ PROP_CLIENT_NAME,
+ PROP_LAST
+};
+
+#define _do_init(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_jack_audio_sink_debug, "jacksink", 0, "jacksink element");
+
+GST_BOILERPLATE_FULL (GstJackAudioSink, gst_jack_audio_sink, GstBaseAudioSink,
+ GST_TYPE_BASE_AUDIO_SINK, _do_init);
+
+static void gst_jack_audio_sink_dispose (GObject * object);
+static void gst_jack_audio_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_jack_audio_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_jack_audio_sink_getcaps (GstBaseSink * bsink);
+static GstRingBuffer *gst_jack_audio_sink_create_ringbuffer (GstBaseAudioSink *
+ sink);
+
+static void
+gst_jack_audio_sink_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details_simple (element_class, "Audio Sink (Jack)",
+ "Sink/Audio", "Output audio to a JACK server",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gst_element_class_add_static_pad_template (element_class,
+ &jackaudiosink_sink_factory);
+}
+
+static void
+gst_jack_audio_sink_class_init (GstJackAudioSinkClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstBaseSinkClass *gstbasesink_class;
+ GstBaseAudioSinkClass *gstbaseaudiosink_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstbasesink_class = (GstBaseSinkClass *) klass;
+ gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
+
+ gobject_class->dispose = gst_jack_audio_sink_dispose;
+ gobject_class->get_property = gst_jack_audio_sink_get_property;
+ gobject_class->set_property = gst_jack_audio_sink_set_property;
+
+ g_object_class_install_property (gobject_class, PROP_CONNECT,
+ g_param_spec_enum ("connect", "Connect",
+ "Specify how the output ports will be connected",
+ GST_TYPE_JACK_CONNECT, DEFAULT_PROP_CONNECT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_SERVER,
+ g_param_spec_string ("server", "Server",
+ "The Jack server to connect to (NULL = default)",
+ DEFAULT_PROP_SERVER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstJackAudioSink:client-name
+ *
+ * The client name to use.
+ *
+ * Since: 0.10.31
+ */
+ g_object_class_install_property (gobject_class, PROP_CLIENT_NAME,
+ g_param_spec_string ("client-name", "Client name",
+ "The client name of the Jack instance (NULL = default)",
+ DEFAULT_PROP_CLIENT_NAME,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_CLIENT,
+ g_param_spec_boxed ("client", "JackClient", "Handle for jack client",
+ GST_TYPE_JACK_CLIENT,
+ GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_jack_audio_sink_getcaps);
+
+ gstbaseaudiosink_class->create_ringbuffer =
+ GST_DEBUG_FUNCPTR (gst_jack_audio_sink_create_ringbuffer);
+
+ /* ref class from a thread-safe context to work around missing bit of
+ * thread-safety in GObject */
+ g_type_class_ref (GST_TYPE_JACK_RING_BUFFER);
+
+ gst_jack_audio_client_init ();
+}
+
+static void
+gst_jack_audio_sink_init (GstJackAudioSink * sink,
+ GstJackAudioSinkClass * g_class)
+{
+ sink->connect = DEFAULT_PROP_CONNECT;
+ sink->server = g_strdup (DEFAULT_PROP_SERVER);
+ sink->jclient = NULL;
+ sink->ports = NULL;
+ sink->port_count = 0;
+ sink->client_name = g_strdup (DEFAULT_PROP_CLIENT_NAME);
+ sink->buffers = NULL;
+}
+
+static void
+gst_jack_audio_sink_dispose (GObject * object)
+{
+ GstJackAudioSink *sink = GST_JACK_AUDIO_SINK (object);
+
+ gst_caps_replace (&sink->caps, NULL);
+
+ if (sink->client_name != NULL) {
+ g_free (sink->client_name);
+ sink->client_name = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_jack_audio_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstJackAudioSink *sink;
+
+ sink = GST_JACK_AUDIO_SINK (object);
+
+ switch (prop_id) {
+ case PROP_CLIENT_NAME:
+ g_free (sink->client_name);
+ sink->client_name = g_value_dup_string (value);
+ break;
+ case PROP_CONNECT:
+ sink->connect = g_value_get_enum (value);
+ break;
+ case PROP_SERVER:
+ g_free (sink->server);
+ sink->server = g_value_dup_string (value);
+ break;
+ case PROP_CLIENT:
+ if (GST_STATE (sink) == GST_STATE_NULL ||
+ GST_STATE (sink) == GST_STATE_READY) {
+ sink->jclient = g_value_get_boxed (value);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_jack_audio_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstJackAudioSink *sink;
+
+ sink = GST_JACK_AUDIO_SINK (object);
+
+ switch (prop_id) {
+ case PROP_CLIENT_NAME:
+ g_value_set_string (value, sink->client_name);
+ break;
+ case PROP_CONNECT:
+ g_value_set_enum (value, sink->connect);
+ break;
+ case PROP_SERVER:
+ g_value_set_string (value, sink->server);
+ break;
+ case PROP_CLIENT:
+ g_value_set_boxed (value, sink->jclient);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstCaps *
+gst_jack_audio_sink_getcaps (GstBaseSink * bsink)
+{
+ GstJackAudioSink *sink = GST_JACK_AUDIO_SINK (bsink);
+ const char **ports;
+ gint min, max;
+ gint rate;
+ jack_client_t *client;
+
+ if (sink->client == NULL)
+ goto no_client;
+
+ client = gst_jack_audio_client_get_client (sink->client);
+
+ if (sink->connect == GST_JACK_CONNECT_AUTO) {
+ /* get a port count, this is the number of channels we can automatically
+ * connect. */
+ ports = jack_get_ports (client, NULL, NULL,
+ JackPortIsPhysical | JackPortIsInput);
+ max = 0;
+ if (ports != NULL) {
+ for (; ports[max]; max++);
+ free (ports);
+ } else
+ max = 0;
+ } else {
+ /* we allow any number of pads, something else is going to connect the
+ * pads. */
+ max = G_MAXINT;
+ }
+ min = MIN (1, max);
+
+ rate = jack_get_sample_rate (client);
+
+ GST_DEBUG_OBJECT (sink, "got %d-%d ports, samplerate: %d", min, max, rate);
+
+ if (!sink->caps) {
+ sink->caps = gst_caps_new_simple ("audio/x-raw-float",
+ "endianness", G_TYPE_INT, G_BYTE_ORDER,
+ "width", G_TYPE_INT, 32,
+ "rate", G_TYPE_INT, rate,
+ "channels", GST_TYPE_INT_RANGE, min, max, NULL);
+ }
+ GST_INFO_OBJECT (sink, "returning caps %" GST_PTR_FORMAT, sink->caps);
+
+ return gst_caps_ref (sink->caps);
+
+ /* ERRORS */
+no_client:
+ {
+ GST_DEBUG_OBJECT (sink, "device not open, using template caps");
+ /* base class will get template caps for us when we return NULL */
+ return NULL;
+ }
+}
+
+static GstRingBuffer *
+gst_jack_audio_sink_create_ringbuffer (GstBaseAudioSink * sink)
+{
+ GstRingBuffer *buffer;
+
+ buffer = g_object_new (GST_TYPE_JACK_RING_BUFFER, NULL);
+ GST_DEBUG_OBJECT (sink, "created ringbuffer @%p", buffer);
+
+ return buffer;
+}
diff --git a/ext/jack/gstjackaudiosink.h b/ext/jack/gstjackaudiosink.h
new file mode 100644
index 0000000..db5fc28
--- /dev/null
+++ b/ext/jack/gstjackaudiosink.h
@@ -0,0 +1,80 @@
+/* GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ *
+ * gstjacksink.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_JACK_AUDIO_SINK_H__
+#define __GST_JACK_AUDIO_SINK_H__
+
+#include <jack/jack.h>
+
+#include <gst/gst.h>
+#include <gst/audio/gstbaseaudiosink.h>
+
+#include "gstjack.h"
+#include "gstjackaudioclient.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_JACK_AUDIO_SINK (gst_jack_audio_sink_get_type())
+#define GST_JACK_AUDIO_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JACK_AUDIO_SINK,GstJackAudioSink))
+#define GST_JACK_AUDIO_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JACK_AUDIO_SINK,GstJackAudioSinkClass))
+#define GST_JACK_AUDIO_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_JACK_AUDIO_SINK,GstJackAudioSinkClass))
+#define GST_IS_JACK_AUDIO_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JACK_AUDIO_SINK))
+#define GST_IS_JACK_AUDIO_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JACK_AUDIO_SINK))
+
+typedef struct _GstJackAudioSink GstJackAudioSink;
+typedef struct _GstJackAudioSinkClass GstJackAudioSinkClass;
+
+/**
+ * GstJackAudioSink:
+ *
+ * Opaque #GstJackAudioSink.
+ */
+struct _GstJackAudioSink {
+ GstBaseAudioSink element;
+
+ /*< private >*/
+ /* cached caps */
+ GstCaps *caps;
+
+ /* properties */
+ GstJackConnect connect;
+ gchar *server;
+ jack_client_t *jclient;
+ gchar *client_name;
+
+ /* our client */
+ GstJackAudioClient *client;
+
+ /* our ports */
+ jack_port_t **ports;
+ int port_count;
+ sample_t **buffers;
+};
+
+struct _GstJackAudioSinkClass {
+ GstBaseAudioSinkClass parent_class;
+};
+
+GType gst_jack_audio_sink_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_JACK_AUDIO_SINK_H__ */
diff --git a/ext/jack/gstjackaudiosrc.c b/ext/jack/gstjackaudiosrc.c
new file mode 100644
index 0000000..3c37970
--- /dev/null
+++ b/ext/jack/gstjackaudiosrc.c
@@ -0,0 +1,924 @@
+/* GStreamer
+ * Copyright (C) 2008 Tristan Matthews <tristan@sat.qc.ca>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-jackaudiosrc
+ * @see_also: #GstBaseAudioSrc, #GstRingBuffer
+ *
+ * A Src that inputs data from Jack ports.
+ *
+ * It will create N Jack ports named in_&lt;name&gt;_&lt;num&gt; where
+ * &lt;name&gt; is the element name and &lt;num&gt; is starting from 1.
+ * Each port corresponds to a gstreamer channel.
+ *
+ * The samplerate as exposed on the caps is always the same as the samplerate of
+ * the jack server.
+ *
+ * When the #GstJackAudioSrc:connect property is set to auto, this element
+ * will try to connect each input port to a random physical jack output pin.
+ *
+ * When the #GstJackAudioSrc:connect property is set to none, the element will
+ * accept any number of output channels and will create (but not connect) an
+ * input port for each channel.
+ *
+ * The element will generate an error when the Jack server is shut down when it
+ * was PAUSED or PLAYING. This element does not support dynamic rate and buffer
+ * size changes at runtime.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch jackaudiosrc connect=0 ! jackaudiosink connect=0
+ * ]| Get audio input into gstreamer from jack.
+ * </refsect2>
+ *
+ * Last reviewed on 2008-07-22 (0.10.4)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst-i18n-plugin.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gstjackaudiosrc.h"
+#include "gstjackringbuffer.h"
+#include "gstjackutil.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_jack_audio_src_debug);
+#define GST_CAT_DEFAULT gst_jack_audio_src_debug
+
+static gboolean
+gst_jack_audio_src_allocate_channels (GstJackAudioSrc * src, gint channels)
+{
+ jack_client_t *client;
+
+ client = gst_jack_audio_client_get_client (src->client);
+
+ /* remove ports we don't need */
+ while (src->port_count > channels)
+ jack_port_unregister (client, src->ports[--src->port_count]);
+
+ /* alloc enough input ports */
+ src->ports = g_realloc (src->ports, sizeof (jack_port_t *) * channels);
+ src->buffers = g_realloc (src->buffers, sizeof (sample_t *) * channels);
+
+ /* create an input port for each channel */
+ while (src->port_count < channels) {
+ gchar *name;
+
+ /* port names start from 1 and are local to the element */
+ name =
+ g_strdup_printf ("in_%s_%d", GST_ELEMENT_NAME (src),
+ src->port_count + 1);
+ src->ports[src->port_count] =
+ jack_port_register (client, name, JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput, 0);
+ if (src->ports[src->port_count] == NULL)
+ return FALSE;
+
+ src->port_count++;
+
+ g_free (name);
+ }
+ return TRUE;
+}
+
+static void
+gst_jack_audio_src_free_channels (GstJackAudioSrc * src)
+{
+ gint res, i = 0;
+ jack_client_t *client;
+
+ client = gst_jack_audio_client_get_client (src->client);
+
+ /* get rid of all ports */
+ while (src->port_count) {
+ GST_LOG_OBJECT (src, "unregister port %d", i);
+ if ((res = jack_port_unregister (client, src->ports[i++])))
+ GST_DEBUG_OBJECT (src, "unregister of port failed (%d)", res);
+
+ src->port_count--;
+ }
+ g_free (src->ports);
+ src->ports = NULL;
+ g_free (src->buffers);
+ src->buffers = NULL;
+}
+
+/* ringbuffer abstract base class */
+static GType
+gst_jack_ring_buffer_get_type (void)
+{
+ static volatile gsize ringbuffer_type = 0;
+
+ if (g_once_init_enter (&ringbuffer_type)) {
+ static const GTypeInfo ringbuffer_info = { sizeof (GstJackRingBufferClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gst_jack_ring_buffer_class_init,
+ NULL,
+ NULL,
+ sizeof (GstJackRingBuffer),
+ 0,
+ (GInstanceInitFunc) gst_jack_ring_buffer_init,
+ NULL
+ };
+ GType tmp = g_type_register_static (GST_TYPE_RING_BUFFER,
+ "GstJackAudioSrcRingBuffer", &ringbuffer_info, 0);
+ g_once_init_leave (&ringbuffer_type, tmp);
+ }
+
+ return (GType) ringbuffer_type;
+}
+
+static void
+gst_jack_ring_buffer_class_init (GstJackRingBufferClass * klass)
+{
+ GstRingBufferClass *gstringbuffer_class;
+
+ gstringbuffer_class = (GstRingBufferClass *) klass;
+
+ ring_parent_class = g_type_class_peek_parent (klass);
+
+ gstringbuffer_class->open_device =
+ GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_open_device);
+ gstringbuffer_class->close_device =
+ GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_close_device);
+ gstringbuffer_class->acquire =
+ GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_acquire);
+ gstringbuffer_class->release =
+ GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_release);
+ gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_start);
+ gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_pause);
+ gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_start);
+ gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_stop);
+
+ gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_delay);
+}
+
+/* this is the callback of jack. This should be RT-safe.
+ * Writes samples from the jack input port's buffer to the gst ring buffer.
+ */
+static int
+jack_process_cb (jack_nframes_t nframes, void *arg)
+{
+ GstJackAudioSrc *src;
+ GstRingBuffer *buf;
+ gint len;
+ guint8 *writeptr;
+ gint writeseg;
+ gint channels, i, j, flen;
+ sample_t *data;
+
+ buf = GST_RING_BUFFER_CAST (arg);
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+ channels = buf->spec.channels;
+
+ /* get input buffers */
+ for (i = 0; i < channels; i++)
+ src->buffers[i] =
+ (sample_t *) jack_port_get_buffer (src->ports[i], nframes);
+
+ if (gst_ring_buffer_prepare_read (buf, &writeseg, &writeptr, &len)) {
+ flen = len / channels;
+
+ /* the number of samples must be exactly the segment size */
+ if (nframes * sizeof (sample_t) != flen)
+ goto wrong_size;
+
+ /* the samples in the jack input buffers have to be interleaved into the
+ * ringbuffer */
+ data = (sample_t *) writeptr;
+ for (i = 0; i < nframes; ++i)
+ for (j = 0; j < channels; ++j)
+ *data++ = src->buffers[j][i];
+
+ GST_DEBUG ("copy %d frames: %p, %d bytes, %d channels", nframes, writeptr,
+ len / channels, channels);
+
+ /* we wrote one segment */
+ gst_ring_buffer_advance (buf, 1);
+ }
+ return 0;
+
+ /* ERRORS */
+wrong_size:
+ {
+ GST_ERROR_OBJECT (src, "nbytes (%d) != flen (%d)",
+ (gint) (nframes * sizeof (sample_t)), flen);
+ return 1;
+ }
+}
+
+/* we error out */
+static int
+jack_sample_rate_cb (jack_nframes_t nframes, void *arg)
+{
+ GstJackAudioSrc *src;
+ GstJackRingBuffer *abuf;
+
+ abuf = GST_JACK_RING_BUFFER_CAST (arg);
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (arg));
+
+ if (abuf->sample_rate != -1 && abuf->sample_rate != nframes)
+ goto not_supported;
+
+ return 0;
+
+ /* ERRORS */
+not_supported:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
+ (NULL), ("Jack changed the sample rate, which is not supported"));
+ return 1;
+ }
+}
+
+/* we error out */
+static int
+jack_buffer_size_cb (jack_nframes_t nframes, void *arg)
+{
+ GstJackAudioSrc *src;
+ GstJackRingBuffer *abuf;
+
+ abuf = GST_JACK_RING_BUFFER_CAST (arg);
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (arg));
+
+ if (abuf->buffer_size != -1 && abuf->buffer_size != nframes)
+ goto not_supported;
+
+ return 0;
+
+ /* ERRORS */
+not_supported:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
+ (NULL), ("Jack changed the buffer size, which is not supported"));
+ return 1;
+ }
+}
+
+static void
+jack_shutdown_cb (void *arg)
+{
+ GstJackAudioSrc *src;
+
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (arg));
+
+ GST_DEBUG_OBJECT (src, "shutdown");
+
+ GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
+ (NULL), ("Jack server shutdown"));
+}
+
+static void
+gst_jack_ring_buffer_init (GstJackRingBuffer * buf,
+ GstJackRingBufferClass * g_class)
+{
+ buf->channels = -1;
+ buf->buffer_size = -1;
+ buf->sample_rate = -1;
+}
+
+/* the _open_device method should make a connection with the server
+*/
+static gboolean
+gst_jack_ring_buffer_open_device (GstRingBuffer * buf)
+{
+ GstJackAudioSrc *src;
+ jack_status_t status = 0;
+ const gchar *name;
+
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+ GST_DEBUG_OBJECT (src, "open");
+
+ if (src->client_name) {
+ name = src->client_name;
+ } else {
+ name = g_get_application_name ();
+ }
+ if (!name)
+ name = "GStreamer";
+
+ src->client = gst_jack_audio_client_new (name, src->server,
+ src->jclient,
+ GST_JACK_CLIENT_SOURCE,
+ jack_shutdown_cb,
+ jack_process_cb, jack_buffer_size_cb, jack_sample_rate_cb, buf, &status);
+ if (src->client == NULL)
+ goto could_not_open;
+
+ GST_DEBUG_OBJECT (src, "opened");
+
+ return TRUE;
+
+ /* ERRORS */
+could_not_open:
+ {
+ if (status & (JackServerFailed | JackFailure)) {
+ GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
+ (_("Jack server not found")),
+ ("Cannot connect to the Jack server (status %d)", status));
+ } else {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+ (NULL), ("Jack client open error (status %d)", status));
+ }
+ return FALSE;
+ }
+}
+
+/* close the connection with the server
+*/
+static gboolean
+gst_jack_ring_buffer_close_device (GstRingBuffer * buf)
+{
+ GstJackAudioSrc *src;
+
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+ GST_DEBUG_OBJECT (src, "close");
+
+ gst_jack_audio_src_free_channels (src);
+ gst_jack_audio_client_free (src->client);
+ src->client = NULL;
+
+ return TRUE;
+}
+
+
+/* allocate a buffer and setup resources to process the audio samples of
+ * the format as specified in @spec.
+ *
+ * We allocate N jack ports, one for each channel. If we are asked to
+ * automatically make a connection with physical ports, we connect as many
+ * ports as there are physical ports, leaving leftover ports unconnected.
+ *
+ * It is assumed that samplerate and number of channels are acceptable since our
+ * getcaps method will always provide correct values. If unacceptable caps are
+ * received for some reason, we fail here.
+ */
+static gboolean
+gst_jack_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
+{
+ GstJackAudioSrc *src;
+ GstJackRingBuffer *abuf;
+ const char **ports;
+ gint sample_rate, buffer_size;
+ gint i, channels, res;
+ jack_client_t *client;
+
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+ abuf = GST_JACK_RING_BUFFER_CAST (buf);
+
+ GST_DEBUG_OBJECT (src, "acquire");
+
+ client = gst_jack_audio_client_get_client (src->client);
+
+ /* sample rate must be that of the server */
+ sample_rate = jack_get_sample_rate (client);
+ if (sample_rate != spec->rate)
+ goto wrong_samplerate;
+
+ channels = spec->channels;
+
+ if (!gst_jack_audio_src_allocate_channels (src, channels))
+ goto out_of_ports;
+
+ gst_jack_set_layout_on_caps (&spec->caps, channels);
+
+ buffer_size = jack_get_buffer_size (client);
+
+ /* the segment size in bytes, this is large enough to hold a buffer of 32bit floats
+ * for all channels */
+ spec->segsize = buffer_size * sizeof (gfloat) * channels;
+ spec->latency_time = gst_util_uint64_scale (spec->segsize,
+ (GST_SECOND / GST_USECOND), spec->rate * spec->bytes_per_sample);
+ /* segtotal based on buffer-time latency */
+ spec->segtotal = spec->buffer_time / spec->latency_time;
+ if (spec->segtotal < 2) {
+ spec->segtotal = 2;
+ spec->buffer_time = spec->latency_time * spec->segtotal;
+ }
+
+ GST_DEBUG_OBJECT (src, "buffer time: %" G_GINT64_FORMAT " usec",
+ spec->buffer_time);
+ GST_DEBUG_OBJECT (src, "latency time: %" G_GINT64_FORMAT " usec",
+ spec->latency_time);
+ GST_DEBUG_OBJECT (src, "buffer_size %d, segsize %d, segtotal %d",
+ buffer_size, spec->segsize, spec->segtotal);
+
+ /* allocate the ringbuffer memory now */
+ buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
+ memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
+
+ if ((res = gst_jack_audio_client_set_active (src->client, TRUE)))
+ goto could_not_activate;
+
+ /* if we need to automatically connect the ports, do so now. We must do this
+ * after activating the client. */
+ if (src->connect == GST_JACK_CONNECT_AUTO
+ || src->connect == GST_JACK_CONNECT_AUTO_FORCED) {
+ /* find all the physical output ports. A physical output port is a port
+ * associated with a hardware device. Someone needs connect to a physical
+ * port in order to capture something. */
+ ports =
+ jack_get_ports (client, NULL, NULL,
+ JackPortIsPhysical | JackPortIsOutput);
+ if (ports == NULL) {
+ /* no ports? fine then we don't do anything except for posting a warning
+ * message. */
+ GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL),
+ ("No physical output ports found, leaving ports unconnected"));
+ goto done;
+ }
+
+ for (i = 0; i < channels; i++) {
+ /* stop when all output ports are exhausted */
+ if (ports[i] == NULL) {
+ /* post a warning that we could not connect all ports */
+ GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL),
+ ("No more physical ports, leaving some ports unconnected"));
+ break;
+ }
+ GST_DEBUG_OBJECT (src, "try connecting to %s",
+ jack_port_name (src->ports[i]));
+
+ /* connect the physical port to a port */
+ res = jack_connect (client, ports[i], jack_port_name (src->ports[i]));
+ if (res != 0 && res != EEXIST)
+ goto cannot_connect;
+ }
+ free (ports);
+ }
+done:
+
+ abuf->sample_rate = sample_rate;
+ abuf->buffer_size = buffer_size;
+ abuf->channels = spec->channels;
+
+ return TRUE;
+
+ /* ERRORS */
+wrong_samplerate:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+ ("Wrong samplerate, server is running at %d and we received %d",
+ sample_rate, spec->rate));
+ return FALSE;
+ }
+out_of_ports:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+ ("Cannot allocate more Jack ports"));
+ return FALSE;
+ }
+could_not_activate:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+ ("Could not activate client (%d:%s)", res, g_strerror (res)));
+ return FALSE;
+ }
+cannot_connect:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+ ("Could not connect input ports to physical ports (%d:%s)",
+ res, g_strerror (res)));
+ free (ports);
+ return FALSE;
+ }
+}
+
+/* function is called with LOCK */
+static gboolean
+gst_jack_ring_buffer_release (GstRingBuffer * buf)
+{
+ GstJackAudioSrc *src;
+ GstJackRingBuffer *abuf;
+ gint res;
+
+ abuf = GST_JACK_RING_BUFFER_CAST (buf);
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+ GST_DEBUG_OBJECT (src, "release");
+
+ if ((res = gst_jack_audio_client_set_active (src->client, FALSE))) {
+ /* we only warn, this means the server is probably shut down and the client
+ * is gone anyway. */
+ GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL),
+ ("Could not deactivate Jack client (%d)", res));
+ }
+
+ abuf->channels = -1;
+ abuf->buffer_size = -1;
+ abuf->sample_rate = -1;
+
+ /* free the buffer */
+ gst_buffer_unref (buf->data);
+ buf->data = NULL;
+
+ return TRUE;
+}
+
+static gboolean
+gst_jack_ring_buffer_start (GstRingBuffer * buf)
+{
+ GstJackAudioSrc *src;
+
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+ GST_DEBUG_OBJECT (src, "start");
+
+ return TRUE;
+}
+
+static gboolean
+gst_jack_ring_buffer_pause (GstRingBuffer * buf)
+{
+ GstJackAudioSrc *src;
+
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+ GST_DEBUG_OBJECT (src, "pause");
+
+ return TRUE;
+}
+
+static gboolean
+gst_jack_ring_buffer_stop (GstRingBuffer * buf)
+{
+ GstJackAudioSrc *src;
+
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+ GST_DEBUG_OBJECT (src, "stop");
+
+ return TRUE;
+}
+
+#if defined (HAVE_JACK_0_120_1) || defined(HAVE_JACK_1_9_7)
+static guint
+gst_jack_ring_buffer_delay (GstRingBuffer * buf)
+{
+ GstJackAudioSrc *src;
+ guint i, res = 0;
+ jack_latency_range_t range;
+
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+ for (i = 0; i < src->port_count; i++) {
+ jack_port_get_latency_range (src->ports[i], JackCaptureLatency, &range);
+ if (range.max > res)
+ res = range.max;
+ }
+
+ GST_DEBUG_OBJECT (src, "delay %u", res);
+
+ return res;
+}
+#else /* !(defined (HAVE_JACK_0_120_1) || defined(HAVE_JACK_1_9_7)) */
+static guint
+gst_jack_ring_buffer_delay (GstRingBuffer * buf)
+{
+ GstJackAudioSrc *src;
+ guint i, res = 0;
+ guint latency;
+ jack_client_t *client;
+
+ src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+ client = gst_jack_audio_client_get_client (src->client);
+
+ for (i = 0; i < src->port_count; i++) {
+ latency = jack_port_get_total_latency (client, src->ports[i]);
+ if (latency > res)
+ res = latency;
+ }
+
+ GST_DEBUG_OBJECT (src, "delay %u", res);
+
+ return res;
+}
+#endif
+
+/* Audiosrc signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+#define DEFAULT_PROP_CONNECT GST_JACK_CONNECT_AUTO
+#define DEFAULT_PROP_SERVER NULL
+#define DEFAULT_PROP_CLIENT_NAME NULL
+
+enum
+{
+ PROP_0,
+ PROP_CONNECT,
+ PROP_SERVER,
+ PROP_CLIENT,
+ PROP_CLIENT_NAME,
+ PROP_LAST
+};
+
+
+/* the capabilities of the inputs and outputs.
+ *
+ * describe the real formats here.
+ */
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw-float, "
+ "endianness = (int) BYTE_ORDER, "
+ "width = (int) 32, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+ );
+
+#define _do_init(bla) \
+ GST_DEBUG_CATEGORY_INIT(gst_jack_audio_src_debug, "jacksrc", 0, "jacksrc element");
+
+GST_BOILERPLATE_FULL (GstJackAudioSrc, gst_jack_audio_src, GstBaseAudioSrc,
+ GST_TYPE_BASE_AUDIO_SRC, _do_init);
+
+static void gst_jack_audio_src_dispose (GObject * object);
+static void gst_jack_audio_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_jack_audio_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_jack_audio_src_getcaps (GstBaseSrc * bsrc);
+static GstRingBuffer *gst_jack_audio_src_create_ringbuffer (GstBaseAudioSrc *
+ src);
+
+/* GObject vmethod implementations */
+
+static void
+gst_jack_audio_src_base_init (gpointer gclass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
+
+ gst_element_class_add_static_pad_template (element_class, &src_factory);
+ gst_element_class_set_details_simple (element_class, "Audio Source (Jack)",
+ "Source/Audio", "Captures audio from a JACK server",
+ "Tristan Matthews <tristan@sat.qc.ca>");
+}
+
+/* initialize the jack_audio_src's class */
+static void
+gst_jack_audio_src_class_init (GstJackAudioSrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstBaseSrcClass *gstbasesrc_class;
+ GstBaseAudioSrcClass *gstbaseaudiosrc_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ gstbasesrc_class = (GstBaseSrcClass *) klass;
+ gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass;
+
+ gobject_class->dispose = gst_jack_audio_src_dispose;
+ gobject_class->set_property = gst_jack_audio_src_set_property;
+ gobject_class->get_property = gst_jack_audio_src_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_CONNECT,
+ g_param_spec_enum ("connect", "Connect",
+ "Specify how the input ports will be connected",
+ GST_TYPE_JACK_CONNECT, DEFAULT_PROP_CONNECT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_SERVER,
+ g_param_spec_string ("server", "Server",
+ "The Jack server to connect to (NULL = default)",
+ DEFAULT_PROP_SERVER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstJackAudioSrc:client-name
+ *
+ * The client name to use.
+ *
+ * Since: 0.10.31
+ */
+ g_object_class_install_property (gobject_class, PROP_CLIENT_NAME,
+ g_param_spec_string ("client-name", "Client name",
+ "The client name of the Jack instance (NULL = default)",
+ DEFAULT_PROP_CLIENT_NAME,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_CLIENT,
+ g_param_spec_boxed ("client", "JackClient", "Handle for jack client",
+ GST_TYPE_JACK_CLIENT,
+ GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_jack_audio_src_getcaps);
+ gstbaseaudiosrc_class->create_ringbuffer =
+ GST_DEBUG_FUNCPTR (gst_jack_audio_src_create_ringbuffer);
+
+ /* ref class from a thread-safe context to work around missing bit of
+ * thread-safety in GObject */
+ g_type_class_ref (GST_TYPE_JACK_RING_BUFFER);
+
+ gst_jack_audio_client_init ();
+}
+
+/* initialize the new element
+ * instantiate pads and add them to element
+ * set pad calback functions
+ * initialize instance structure
+ */
+static void
+gst_jack_audio_src_init (GstJackAudioSrc * src, GstJackAudioSrcClass * gclass)
+{
+ //gst_base_src_set_live(GST_BASE_SRC (src), TRUE);
+ src->connect = DEFAULT_PROP_CONNECT;
+ src->server = g_strdup (DEFAULT_PROP_SERVER);
+ src->jclient = NULL;
+ src->ports = NULL;
+ src->port_count = 0;
+ src->buffers = NULL;
+ src->client_name = g_strdup (DEFAULT_PROP_CLIENT_NAME);
+}
+
+static void
+gst_jack_audio_src_dispose (GObject * object)
+{
+ GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object);
+
+ gst_caps_replace (&src->caps, NULL);
+
+ if (src->client_name != NULL) {
+ g_free (src->client_name);
+ src->client_name = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_jack_audio_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object);
+
+ switch (prop_id) {
+ case PROP_CLIENT_NAME:
+ g_free (src->client_name);
+ src->client_name = g_value_dup_string (value);
+ break;
+ case PROP_CONNECT:
+ src->connect = g_value_get_enum (value);
+ break;
+ case PROP_SERVER:
+ g_free (src->server);
+ src->server = g_value_dup_string (value);
+ break;
+ case PROP_CLIENT:
+ if (GST_STATE (src) == GST_STATE_NULL ||
+ GST_STATE (src) == GST_STATE_READY) {
+ src->jclient = g_value_get_boxed (value);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_jack_audio_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object);
+
+ switch (prop_id) {
+ case PROP_CLIENT_NAME:
+ g_value_set_string (value, src->client_name);
+ break;
+ case PROP_CONNECT:
+ g_value_set_enum (value, src->connect);
+ break;
+ case PROP_SERVER:
+ g_value_set_string (value, src->server);
+ break;
+ case PROP_CLIENT:
+ g_value_set_boxed (value, src->jclient);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstCaps *
+gst_jack_audio_src_getcaps (GstBaseSrc * bsrc)
+{
+ GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (bsrc);
+ const char **ports;
+ gint min, max;
+ gint rate;
+ jack_client_t *client;
+
+ if (src->client == NULL)
+ goto no_client;
+
+ client = gst_jack_audio_client_get_client (src->client);
+
+ if (src->connect == GST_JACK_CONNECT_AUTO) {
+ /* get a port count, this is the number of channels we can automatically
+ * connect. */
+ ports = jack_get_ports (client, NULL, NULL,
+ JackPortIsPhysical | JackPortIsOutput);
+ max = 0;
+ if (ports != NULL) {
+ for (; ports[max]; max++);
+
+ free (ports);
+ } else
+ max = 0;
+ } else {
+ /* we allow any number of pads, something else is going to connect the
+ * pads. */
+ max = G_MAXINT;
+ }
+ min = MIN (1, max);
+
+ rate = jack_get_sample_rate (client);
+
+ GST_DEBUG_OBJECT (src, "got %d-%d ports, samplerate: %d", min, max, rate);
+
+ if (!src->caps) {
+ src->caps = gst_caps_new_simple ("audio/x-raw-float",
+ "endianness", G_TYPE_INT, G_BYTE_ORDER,
+ "width", G_TYPE_INT, 32,
+ "rate", G_TYPE_INT, rate,
+ "channels", GST_TYPE_INT_RANGE, min, max, NULL);
+ }
+ GST_INFO_OBJECT (src, "returning caps %" GST_PTR_FORMAT, src->caps);
+
+ return gst_caps_ref (src->caps);
+
+ /* ERRORS */
+no_client:
+ {
+ GST_DEBUG_OBJECT (src, "device not open, using template caps");
+ /* base class will get template caps for us when we return NULL */
+ return NULL;
+ }
+}
+
+static GstRingBuffer *
+gst_jack_audio_src_create_ringbuffer (GstBaseAudioSrc * src)
+{
+ GstRingBuffer *buffer;
+
+ buffer = g_object_new (GST_TYPE_JACK_RING_BUFFER, NULL);
+ GST_DEBUG_OBJECT (src, "created ringbuffer @%p", buffer);
+
+ return buffer;
+}
diff --git a/ext/jack/gstjackaudiosrc.h b/ext/jack/gstjackaudiosrc.h
new file mode 100644
index 0000000..b69a4d6
--- /dev/null
+++ b/ext/jack/gstjackaudiosrc.h
@@ -0,0 +1,98 @@
+/* GStreamer
+ * Copyright (C) 2008 Tristan Matthews <tristan@sat.qc.ca>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_JACK_AUDIO_SRC_H__
+#define __GST_JACK_AUDIO_SRC_H__
+
+#include <jack/jack.h>
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosrc.h>
+
+#include "gstjackaudioclient.h"
+#include "gstjack.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_JACK_AUDIO_SRC (gst_jack_audio_src_get_type())
+#define GST_JACK_AUDIO_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JACK_AUDIO_SRC,GstJackAudioSrc))
+#define GST_JACK_AUDIO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JACK_AUDIO_SRC,GstJackAudioSrcClass))
+#define GST_JACK_AUDIO_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_JACK_AUDIO_SRC,GstJackAudioSrcClass))
+#define GST_IS_JACK_AUDIO_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JACK_AUDIO_SRC))
+#define GST_IS_JACK_AUDIO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JACK_AUDIO_SRC))
+
+typedef struct _GstJackAudioSrc GstJackAudioSrc;
+typedef struct _GstJackAudioSrcClass GstJackAudioSrcClass;
+
+struct _GstJackAudioSrc
+{
+ GstBaseAudioSrc src;
+
+ /*< private >*/
+ /* cached caps */
+ GstCaps *caps;
+
+ /* properties */
+ GstJackConnect connect;
+ gchar *server;
+ jack_client_t *jclient;
+ gchar *client_name;
+
+ /* our client */
+ GstJackAudioClient *client;
+
+ /* our ports */
+ jack_port_t **ports;
+ int port_count;
+ sample_t **buffers;
+};
+
+struct _GstJackAudioSrcClass
+{
+ GstBaseAudioSrcClass parent_class;
+};
+
+GType gst_jack_audio_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_JACK_AUDIO_SRC_H__ */
diff --git a/ext/jack/gstjackringbuffer.h b/ext/jack/gstjackringbuffer.h
new file mode 100644
index 0000000..266fdfa
--- /dev/null
+++ b/ext/jack/gstjackringbuffer.h
@@ -0,0 +1,88 @@
+/*
+ * GStreamer
+ * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
+ * Copyright (C) 2008 Tristan Matthews <tristan@sat.qc.ca>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_JACK_RING_BUFFER_H__
+#define __GST_JACK_RING_BUFFER_H__
+
+#define GST_TYPE_JACK_RING_BUFFER (gst_jack_ring_buffer_get_type())
+#define GST_JACK_RING_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JACK_RING_BUFFER,GstJackRingBuffer))
+#define GST_JACK_RING_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JACK_RING_BUFFER,GstJackRingBufferClass))
+#define GST_JACK_RING_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_JACK_RING_BUFFER,GstJackRingBufferClass))
+#define GST_JACK_RING_BUFFER_CAST(obj) ((GstJackRingBuffer *)obj)
+#define GST_IS_JACK_RING_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JACK_RING_BUFFER))
+#define GST_IS_JACK_RING_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JACK_RING_BUFFER))
+
+typedef struct _GstJackRingBuffer GstJackRingBuffer;
+typedef struct _GstJackRingBufferClass GstJackRingBufferClass;
+
+struct _GstJackRingBuffer
+{
+ GstRingBuffer object;
+
+ gint sample_rate;
+ gint buffer_size;
+ gint channels;
+};
+
+struct _GstJackRingBufferClass
+{
+ GstRingBufferClass parent_class;
+};
+
+static void gst_jack_ring_buffer_class_init(GstJackRingBufferClass * klass);
+static void gst_jack_ring_buffer_init(GstJackRingBuffer * ringbuffer,
+ GstJackRingBufferClass * klass);
+
+static GstRingBufferClass *ring_parent_class = NULL;
+
+static gboolean gst_jack_ring_buffer_open_device(GstRingBuffer * buf);
+static gboolean gst_jack_ring_buffer_close_device(GstRingBuffer * buf);
+static gboolean gst_jack_ring_buffer_acquire(GstRingBuffer * buf,GstRingBufferSpec * spec);
+static gboolean gst_jack_ring_buffer_release(GstRingBuffer * buf);
+static gboolean gst_jack_ring_buffer_start(GstRingBuffer * buf);
+static gboolean gst_jack_ring_buffer_pause(GstRingBuffer * buf);
+static gboolean gst_jack_ring_buffer_stop(GstRingBuffer * buf);
+static guint gst_jack_ring_buffer_delay(GstRingBuffer * buf);
+
+#endif
diff --git a/ext/jack/gstjackutil.c b/ext/jack/gstjackutil.c
new file mode 100644
index 0000000..cde84d8
--- /dev/null
+++ b/ext/jack/gstjackutil.c
@@ -0,0 +1,114 @@
+/* GStreamer Jack utility functions
+ * Copyright (C) 2010 Tristan Matthews <tristan@sat.qc.ca>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gstjackutil.h"
+#include <gst/audio/multichannel.h>
+
+static const GstAudioChannelPosition default_positions[8][8] = {
+ /* 1 channel */
+ {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
+ },
+ /* 2 channels */
+ {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ },
+ /* 3 channels (2.1) */
+ {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_LFE, /* or FRONT_CENTER for 3.0? */
+ },
+ /* 4 channels (4.0 or 3.1?) */
+ {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ },
+ /* 5 channels */
+ {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ },
+ /* 6 channels */
+ {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE,
+ },
+ /* 7 channels */
+ {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE,
+ GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
+ },
+ /* 8 channels */
+ {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+ }
+};
+
+
+/* if channels are less than or equal to 8, we set a default layout,
+ * otherwise set layout to an array of GST_AUDIO_CHANNEL_POSITION_NONE */
+void
+gst_jack_set_layout_on_caps (GstCaps ** caps, gint channels)
+{
+ int c;
+ GValue pos = { 0 };
+ GValue chanpos = { 0 };
+ gst_caps_unref (*caps);
+
+ if (channels <= 8) {
+ g_assert (channels >= 1);
+ gst_audio_set_channel_positions (gst_caps_get_structure (*caps, 0),
+ default_positions[channels - 1]);
+ } else {
+ g_value_init (&chanpos, GST_TYPE_ARRAY);
+ g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
+ for (c = 0; c < channels; c++) {
+ g_value_set_enum (&pos, GST_AUDIO_CHANNEL_POSITION_NONE);
+ gst_value_array_append_value (&chanpos, &pos);
+ }
+ g_value_unset (&pos);
+ gst_structure_set_value (gst_caps_get_structure (*caps, 0),
+ "channel-positions", &chanpos);
+ g_value_unset (&chanpos);
+ }
+ gst_caps_ref (*caps);
+}
diff --git a/ext/jack/gstjackutil.h b/ext/jack/gstjackutil.h
new file mode 100644
index 0000000..e330afd
--- /dev/null
+++ b/ext/jack/gstjackutil.h
@@ -0,0 +1,30 @@
+/* GStreamer
+ * Copyright (C) 2010 Tristan Matthews <tristan@sat.qc.ca>
+ *
+ * gstjackutil.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GST_JACK_UTIL_H_
+#define _GST_JACK_UTIL_H_
+
+#include <gst/gst.h>
+
+void
+gst_jack_set_layout_on_caps (GstCaps **caps, gint channels);
+
+#endif // _GST_JACK_UTIL_H_
diff --git a/ext/jpeg/Makefile.am b/ext/jpeg/Makefile.am
new file mode 100644
index 0000000..a72f12f
--- /dev/null
+++ b/ext/jpeg/Makefile.am
@@ -0,0 +1,21 @@
+plugin_LTLIBRARIES = libgstjpeg.la
+
+libgstjpeg_la_SOURCES = \
+ gstjpeg.c \
+ gstjpegenc.c \
+ gstjpegdec.c \
+ gstsmokeenc.c \
+ smokecodec.c \
+ gstsmokedec.c
+
+libgstjpeg_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstjpeg_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) -lgstvideo-$(GST_MAJORMINOR) \
+ $(JPEG_LIBS) $(LIBM)
+libgstjpeg_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstjpeg_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = \
+ gstjpeg.h \
+ gstjpegdec.h gstjpegenc.h \
+ gstsmokeenc.h gstsmokedec.h \
+ smokecodec.h smokeformat.h
diff --git a/ext/jpeg/Makefile.in b/ext/jpeg/Makefile.in
new file mode 100644
index 0000000..3cc176c
--- /dev/null
+++ b/ext/jpeg/Makefile.in
@@ -0,0 +1,863 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/jpeg
+DIST_COMMON = README $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstjpeg_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libgstjpeg_la_OBJECTS = libgstjpeg_la-gstjpeg.lo \
+ libgstjpeg_la-gstjpegenc.lo libgstjpeg_la-gstjpegdec.lo \
+ libgstjpeg_la-gstsmokeenc.lo libgstjpeg_la-smokecodec.lo \
+ libgstjpeg_la-gstsmokedec.lo
+libgstjpeg_la_OBJECTS = $(am_libgstjpeg_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstjpeg_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstjpeg_la_CFLAGS) $(CFLAGS) \
+ $(libgstjpeg_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstjpeg_la_SOURCES)
+DIST_SOURCES = $(libgstjpeg_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstjpeg.la
+libgstjpeg_la_SOURCES = \
+ gstjpeg.c \
+ gstjpegenc.c \
+ gstjpegdec.c \
+ gstsmokeenc.c \
+ smokecodec.c \
+ gstsmokedec.c
+
+libgstjpeg_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstjpeg_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) -lgstvideo-$(GST_MAJORMINOR) \
+ $(JPEG_LIBS) $(LIBM)
+
+libgstjpeg_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstjpeg_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = \
+ gstjpeg.h \
+ gstjpegdec.h gstjpegenc.h \
+ gstsmokeenc.h gstsmokedec.h \
+ smokecodec.h smokeformat.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/jpeg/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/jpeg/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstjpeg.la: $(libgstjpeg_la_OBJECTS) $(libgstjpeg_la_DEPENDENCIES) $(EXTRA_libgstjpeg_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstjpeg_la_LINK) -rpath $(plugindir) $(libgstjpeg_la_OBJECTS) $(libgstjpeg_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstjpeg_la-gstjpeg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstjpeg_la-gstjpegdec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstjpeg_la-gstjpegenc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstjpeg_la-gstsmokedec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstjpeg_la-gstsmokeenc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstjpeg_la-smokecodec.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstjpeg_la-gstjpeg.lo: gstjpeg.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjpeg_la_CFLAGS) $(CFLAGS) -MT libgstjpeg_la-gstjpeg.lo -MD -MP -MF $(DEPDIR)/libgstjpeg_la-gstjpeg.Tpo -c -o libgstjpeg_la-gstjpeg.lo `test -f 'gstjpeg.c' || echo '$(srcdir)/'`gstjpeg.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstjpeg_la-gstjpeg.Tpo $(DEPDIR)/libgstjpeg_la-gstjpeg.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstjpeg.c' object='libgstjpeg_la-gstjpeg.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjpeg_la_CFLAGS) $(CFLAGS) -c -o libgstjpeg_la-gstjpeg.lo `test -f 'gstjpeg.c' || echo '$(srcdir)/'`gstjpeg.c
+
+libgstjpeg_la-gstjpegenc.lo: gstjpegenc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjpeg_la_CFLAGS) $(CFLAGS) -MT libgstjpeg_la-gstjpegenc.lo -MD -MP -MF $(DEPDIR)/libgstjpeg_la-gstjpegenc.Tpo -c -o libgstjpeg_la-gstjpegenc.lo `test -f 'gstjpegenc.c' || echo '$(srcdir)/'`gstjpegenc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstjpeg_la-gstjpegenc.Tpo $(DEPDIR)/libgstjpeg_la-gstjpegenc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstjpegenc.c' object='libgstjpeg_la-gstjpegenc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjpeg_la_CFLAGS) $(CFLAGS) -c -o libgstjpeg_la-gstjpegenc.lo `test -f 'gstjpegenc.c' || echo '$(srcdir)/'`gstjpegenc.c
+
+libgstjpeg_la-gstjpegdec.lo: gstjpegdec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjpeg_la_CFLAGS) $(CFLAGS) -MT libgstjpeg_la-gstjpegdec.lo -MD -MP -MF $(DEPDIR)/libgstjpeg_la-gstjpegdec.Tpo -c -o libgstjpeg_la-gstjpegdec.lo `test -f 'gstjpegdec.c' || echo '$(srcdir)/'`gstjpegdec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstjpeg_la-gstjpegdec.Tpo $(DEPDIR)/libgstjpeg_la-gstjpegdec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstjpegdec.c' object='libgstjpeg_la-gstjpegdec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjpeg_la_CFLAGS) $(CFLAGS) -c -o libgstjpeg_la-gstjpegdec.lo `test -f 'gstjpegdec.c' || echo '$(srcdir)/'`gstjpegdec.c
+
+libgstjpeg_la-gstsmokeenc.lo: gstsmokeenc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjpeg_la_CFLAGS) $(CFLAGS) -MT libgstjpeg_la-gstsmokeenc.lo -MD -MP -MF $(DEPDIR)/libgstjpeg_la-gstsmokeenc.Tpo -c -o libgstjpeg_la-gstsmokeenc.lo `test -f 'gstsmokeenc.c' || echo '$(srcdir)/'`gstsmokeenc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstjpeg_la-gstsmokeenc.Tpo $(DEPDIR)/libgstjpeg_la-gstsmokeenc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsmokeenc.c' object='libgstjpeg_la-gstsmokeenc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjpeg_la_CFLAGS) $(CFLAGS) -c -o libgstjpeg_la-gstsmokeenc.lo `test -f 'gstsmokeenc.c' || echo '$(srcdir)/'`gstsmokeenc.c
+
+libgstjpeg_la-smokecodec.lo: smokecodec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjpeg_la_CFLAGS) $(CFLAGS) -MT libgstjpeg_la-smokecodec.lo -MD -MP -MF $(DEPDIR)/libgstjpeg_la-smokecodec.Tpo -c -o libgstjpeg_la-smokecodec.lo `test -f 'smokecodec.c' || echo '$(srcdir)/'`smokecodec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstjpeg_la-smokecodec.Tpo $(DEPDIR)/libgstjpeg_la-smokecodec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='smokecodec.c' object='libgstjpeg_la-smokecodec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjpeg_la_CFLAGS) $(CFLAGS) -c -o libgstjpeg_la-smokecodec.lo `test -f 'smokecodec.c' || echo '$(srcdir)/'`smokecodec.c
+
+libgstjpeg_la-gstsmokedec.lo: gstsmokedec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjpeg_la_CFLAGS) $(CFLAGS) -MT libgstjpeg_la-gstsmokedec.lo -MD -MP -MF $(DEPDIR)/libgstjpeg_la-gstsmokedec.Tpo -c -o libgstjpeg_la-gstsmokedec.lo `test -f 'gstsmokedec.c' || echo '$(srcdir)/'`gstsmokedec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstjpeg_la-gstsmokedec.Tpo $(DEPDIR)/libgstjpeg_la-gstsmokedec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsmokedec.c' object='libgstjpeg_la-gstsmokedec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstjpeg_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstjpeg_la_CFLAGS) $(CFLAGS) -c -o libgstjpeg_la-gstsmokedec.lo `test -f 'gstsmokedec.c' || echo '$(srcdir)/'`gstsmokedec.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/jpeg/README b/ext/jpeg/README
new file mode 100644
index 0000000..ffa1d0c
--- /dev/null
+++ b/ext/jpeg/README
@@ -0,0 +1,20 @@
+The Smoke Codec
+---------------
+
+This is a very simple compression algorithm I was toying with when doing a
+Java based player. Decoding a JPEG in Java has acceptable speed so this codec
+tries to exploit that feature. The algorithm first compares the last and the
+new image and finds all 16x16 blocks that have a squared difference bigger than
+a configurable threshold. Then all these blocks are compressed into an NxM JPEG.
+The quality of the JPEG is inversely proportional to the number of blocks, this
+way, the picture quality degrades with heavy motion scenes but the bitrate stays
+more or less constant.
+Decoding decompresses the JPEG and then updates the old picture with the new
+blocks.
+
+
+TODO:
+----
+- make format extensible
+- motion vectors
+- do some real bitrate control
diff --git a/ext/jpeg/gstjpeg.c b/ext/jpeg/gstjpeg.c
new file mode 100644
index 0000000..b9d6e04
--- /dev/null
+++ b/ext/jpeg/gstjpeg.c
@@ -0,0 +1,77 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+
+#include "gstjpeg.h"
+#include "gstjpegdec.h"
+#include "gstjpegenc.h"
+#include "gstsmokeenc.h"
+#include "gstsmokedec.h"
+
+GType
+gst_idct_method_get_type (void)
+{
+ static GType idct_method_type = 0;
+ static const GEnumValue idct_method[] = {
+ {JDCT_ISLOW, "Slow but accurate integer algorithm", "islow"},
+ {JDCT_IFAST, "Faster, less accurate integer method", "ifast"},
+ {JDCT_FLOAT, "Floating-point: accurate, fast on fast HW", "float"},
+ {0, NULL, NULL},
+ };
+
+ if (!idct_method_type) {
+ idct_method_type = g_enum_register_static ("GstIDCTMethod", idct_method);
+ }
+ return idct_method_type;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+
+ if (!gst_element_register (plugin, "jpegenc", GST_RANK_PRIMARY,
+ GST_TYPE_JPEGENC))
+ return FALSE;
+
+ if (!gst_element_register (plugin, "jpegdec", GST_RANK_PRIMARY,
+ GST_TYPE_JPEG_DEC))
+ return FALSE;
+
+ if (!gst_element_register (plugin, "smokeenc", GST_RANK_PRIMARY,
+ GST_TYPE_SMOKEENC))
+ return FALSE;
+
+ if (!gst_element_register (plugin, "smokedec", GST_RANK_PRIMARY,
+ GST_TYPE_SMOKEDEC))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "jpeg",
+ "JPeg plugin library",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/jpeg/gstjpeg.h b/ext/jpeg/gstjpeg.h
new file mode 100644
index 0000000..8b20199
--- /dev/null
+++ b/ext/jpeg/gstjpeg.h
@@ -0,0 +1,35 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_JPEG_H__
+#define __GST_JPEG_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_IDCT_METHOD (gst_idct_method_get_type())
+GType gst_idct_method_get_type (void);
+
+
+G_END_DECLS
+
+#endif /* __GST_JPEG_H__ */
diff --git a/ext/jpeg/gstjpegdec.c b/ext/jpeg/gstjpegdec.c
new file mode 100644
index 0000000..18cf20d
--- /dev/null
+++ b/ext/jpeg/gstjpegdec.c
@@ -0,0 +1,1873 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-jpegdec
+ *
+ * Decodes jpeg images.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch -v v4l2src ! jpegdec ! ffmpegcolorspace ! xvimagesink
+ * ]| The above pipeline reads a motion JPEG stream from a v4l2 camera
+ * and renders it to the screen.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+
+#include "gstjpegdec.h"
+#include "gstjpeg.h"
+#include <gst/video/video.h>
+#include "gst/gst-i18n-plugin.h"
+#include <jerror.h>
+
+#define MIN_WIDTH 1
+#define MAX_WIDTH 65535
+#define MIN_HEIGHT 1
+#define MAX_HEIGHT 65535
+
+#define CINFO_GET_JPEGDEC(cinfo_ptr) \
+ (((struct GstJpegDecSourceMgr*)((cinfo_ptr)->src))->dec)
+
+#define JPEG_DEFAULT_IDCT_METHOD JDCT_FASTEST
+#define JPEG_DEFAULT_MAX_ERRORS 0
+
+enum
+{
+ PROP_0,
+ PROP_IDCT_METHOD,
+ PROP_MAX_ERRORS
+};
+
+/* *INDENT-OFF* */
+static GstStaticPadTemplate gst_jpeg_dec_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420") "; "
+ GST_VIDEO_CAPS_RGB "; " GST_VIDEO_CAPS_BGR "; "
+ GST_VIDEO_CAPS_RGBx "; " GST_VIDEO_CAPS_xRGB "; "
+ GST_VIDEO_CAPS_BGRx "; " GST_VIDEO_CAPS_xBGR "; "
+ GST_VIDEO_CAPS_GRAY8)
+ );
+/* *INDENT-ON* */
+
+/* FIXME: sof-marker is for IJG libjpeg 8, should be different for 6.2 */
+static GstStaticPadTemplate gst_jpeg_dec_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("image/jpeg, "
+ "width = (int) [ " G_STRINGIFY (MIN_WIDTH) ", " G_STRINGIFY (MAX_WIDTH)
+ " ], " "height = (int) [ " G_STRINGIFY (MIN_HEIGHT) ", "
+ G_STRINGIFY (MAX_HEIGHT) " ], framerate = (fraction) [ 0/1, MAX ], "
+ "sof-marker = (int) { 0, 1, 2, 5, 6, 7, 9, 10, 13, 14 }")
+ );
+
+GST_DEBUG_CATEGORY_STATIC (jpeg_dec_debug);
+#define GST_CAT_DEFAULT jpeg_dec_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
+
+/* These macros are adapted from videotestsrc.c
+ * and/or gst-plugins/gst/games/gstvideoimage.c */
+#define I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
+#define I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
+#define I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2)
+
+#define I420_Y_OFFSET(w,h) (0)
+#define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
+#define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
+
+#define I420_SIZE(w,h) (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
+
+static GstElementClass *parent_class; /* NULL */
+
+static void gst_jpeg_dec_base_init (gpointer g_class);
+static void gst_jpeg_dec_class_init (GstJpegDecClass * klass);
+static void gst_jpeg_dec_init (GstJpegDec * jpegdec);
+
+static void gst_jpeg_dec_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_jpeg_dec_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_jpeg_dec_setcaps (GstPad * pad, GstCaps * caps);
+static GstCaps *gst_jpeg_dec_getcaps (GstPad * pad);
+static gboolean gst_jpeg_dec_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_jpeg_dec_src_event (GstPad * pad, GstEvent * event);
+static GstStateChangeReturn gst_jpeg_dec_change_state (GstElement * element,
+ GstStateChange transition);
+static void gst_jpeg_dec_update_qos (GstJpegDec * dec, gdouble proportion,
+ GstClockTimeDiff diff, GstClockTime ts);
+static void gst_jpeg_dec_reset_qos (GstJpegDec * dec);
+static void gst_jpeg_dec_read_qos (GstJpegDec * dec, gdouble * proportion,
+ GstClockTime * time);
+
+GType
+gst_jpeg_dec_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo jpeg_dec_info = {
+ sizeof (GstJpegDecClass),
+ (GBaseInitFunc) gst_jpeg_dec_base_init,
+ NULL,
+ (GClassInitFunc) gst_jpeg_dec_class_init,
+ NULL,
+ NULL,
+ sizeof (GstJpegDec),
+ 0,
+ (GInstanceInitFunc) gst_jpeg_dec_init,
+ };
+
+ type = g_type_register_static (GST_TYPE_ELEMENT, "GstJpegDec",
+ &jpeg_dec_info, 0);
+ }
+ return type;
+}
+
+static void
+gst_jpeg_dec_finalize (GObject * object)
+{
+ GstJpegDec *dec = GST_JPEG_DEC (object);
+
+ jpeg_destroy_decompress (&dec->cinfo);
+
+ g_object_unref (dec->adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_jpeg_dec_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_jpeg_dec_src_pad_template);
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_jpeg_dec_sink_pad_template);
+ gst_element_class_set_details_simple (element_class, "JPEG image decoder",
+ "Codec/Decoder/Image",
+ "Decode images from JPEG format", "Wim Taymans <wim@fluendo.com>");
+}
+
+static void
+gst_jpeg_dec_class_init (GstJpegDecClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GObjectClass *gobject_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gobject_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->finalize = gst_jpeg_dec_finalize;
+ gobject_class->set_property = gst_jpeg_dec_set_property;
+ gobject_class->get_property = gst_jpeg_dec_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_IDCT_METHOD,
+ g_param_spec_enum ("idct-method", "IDCT Method",
+ "The IDCT algorithm to use", GST_TYPE_IDCT_METHOD,
+ JPEG_DEFAULT_IDCT_METHOD,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstJpegDec:max-errors
+ *
+ * Error out after receiving N consecutive decoding errors
+ * (-1 = never error out, 0 = automatic, 1 = fail on first error, etc.)
+ *
+ * Since: 0.10.27
+ **/
+ g_object_class_install_property (gobject_class, PROP_MAX_ERRORS,
+ g_param_spec_int ("max-errors", "Maximum Consecutive Decoding Errors",
+ "Error out after receiving N consecutive decoding errors "
+ "(-1 = never fail, 0 = automatic, 1 = fail on first error)",
+ -1, G_MAXINT, JPEG_DEFAULT_MAX_ERRORS,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_jpeg_dec_change_state);
+
+ GST_DEBUG_CATEGORY_INIT (jpeg_dec_debug, "jpegdec", 0, "JPEG decoder");
+ GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
+}
+
+static void
+gst_jpeg_dec_clear_error (GstJpegDec * dec)
+{
+ g_free (dec->error_msg);
+ dec->error_msg = NULL;
+ dec->error_line = 0;
+ dec->error_func = NULL;
+}
+
+static void
+gst_jpeg_dec_set_error_va (GstJpegDec * dec, const gchar * func, gint line,
+ const gchar * debug_msg_format, va_list args)
+{
+#ifndef GST_DISABLE_GST_DEBUG
+ gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_WARNING, __FILE__, func,
+ line, (GObject *) dec, debug_msg_format, args);
+#endif
+
+ g_free (dec->error_msg);
+ if (debug_msg_format)
+ dec->error_msg = g_strdup_vprintf (debug_msg_format, args);
+ else
+ dec->error_msg = NULL;
+
+ dec->error_line = line;
+ dec->error_func = func;
+}
+
+static void
+gst_jpeg_dec_set_error (GstJpegDec * dec, const gchar * func, gint line,
+ const gchar * debug_msg_format, ...)
+{
+ va_list va;
+
+ va_start (va, debug_msg_format);
+ gst_jpeg_dec_set_error_va (dec, func, line, debug_msg_format, va);
+ va_end (va);
+}
+
+static GstFlowReturn
+gst_jpeg_dec_post_error_or_warning (GstJpegDec * dec)
+{
+ GstFlowReturn ret;
+ int max_errors;
+
+ ++dec->error_count;
+ max_errors = g_atomic_int_get (&dec->max_errors);
+
+ if (max_errors < 0) {
+ ret = GST_FLOW_OK;
+ } else if (max_errors == 0) {
+ /* FIXME: do something more clever in "automatic mode" */
+ if (dec->packetized) {
+ ret = (dec->error_count < 3) ? GST_FLOW_OK : GST_FLOW_ERROR;
+ } else {
+ ret = GST_FLOW_ERROR;
+ }
+ } else {
+ ret = (dec->error_count < max_errors) ? GST_FLOW_OK : GST_FLOW_ERROR;
+ }
+
+ GST_INFO_OBJECT (dec, "decoding error %d/%d (%s)", dec->error_count,
+ max_errors, (ret == GST_FLOW_OK) ? "ignoring error" : "erroring out");
+
+ gst_element_message_full (GST_ELEMENT (dec),
+ (ret == GST_FLOW_OK) ? GST_MESSAGE_WARNING : GST_MESSAGE_ERROR,
+ GST_STREAM_ERROR, GST_STREAM_ERROR_DECODE,
+ g_strdup (_("Failed to decode JPEG image")), dec->error_msg,
+ __FILE__, dec->error_func, dec->error_line);
+
+ dec->error_msg = NULL;
+ gst_jpeg_dec_clear_error (dec);
+ return ret;
+}
+
+static boolean
+gst_jpeg_dec_fill_input_buffer (j_decompress_ptr cinfo)
+{
+ GstJpegDec *dec;
+ guint av;
+
+ dec = CINFO_GET_JPEGDEC (cinfo);
+ g_return_val_if_fail (dec != NULL, FALSE);
+
+ av = gst_adapter_available_fast (dec->adapter);
+ GST_DEBUG_OBJECT (dec, "fill_input_buffer: fast av=%u, remaining=%u", av,
+ dec->rem_img_len);
+
+ if (av == 0) {
+ GST_DEBUG_OBJECT (dec, "Out of data");
+ return FALSE;
+ }
+
+ if (dec->rem_img_len < av)
+ av = dec->rem_img_len;
+ dec->rem_img_len -= av;
+
+ g_free (dec->cur_buf);
+ dec->cur_buf = gst_adapter_take (dec->adapter, av);
+
+ cinfo->src->next_input_byte = dec->cur_buf;
+ cinfo->src->bytes_in_buffer = av;
+
+ return TRUE;
+}
+
+static void
+gst_jpeg_dec_init_source (j_decompress_ptr cinfo)
+{
+ GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "init_source");
+}
+
+
+static void
+gst_jpeg_dec_skip_input_data (j_decompress_ptr cinfo, glong num_bytes)
+{
+ GstJpegDec *dec = CINFO_GET_JPEGDEC (cinfo);
+
+ GST_DEBUG_OBJECT (dec, "skip %ld bytes", num_bytes);
+
+ if (num_bytes > 0 && cinfo->src->bytes_in_buffer >= num_bytes) {
+ cinfo->src->next_input_byte += (size_t) num_bytes;
+ cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
+ } else if (num_bytes > 0) {
+ gint available;
+
+ num_bytes -= cinfo->src->bytes_in_buffer;
+ cinfo->src->next_input_byte += (size_t) cinfo->src->bytes_in_buffer;
+ cinfo->src->bytes_in_buffer = 0;
+
+ available = gst_adapter_available (dec->adapter);
+ if (available < num_bytes || available < dec->rem_img_len) {
+ GST_WARNING_OBJECT (dec, "Less bytes to skip than available in the "
+ "adapter or the remaining image length %ld < %d or %u",
+ num_bytes, available, dec->rem_img_len);
+ }
+ num_bytes = MIN (MIN (num_bytes, available), dec->rem_img_len);
+ gst_adapter_flush (dec->adapter, num_bytes);
+ dec->rem_img_len -= num_bytes;
+ }
+}
+
+static boolean
+gst_jpeg_dec_resync_to_restart (j_decompress_ptr cinfo, gint desired)
+{
+ GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "resync_to_start");
+ return TRUE;
+}
+
+static void
+gst_jpeg_dec_term_source (j_decompress_ptr cinfo)
+{
+ GST_LOG_OBJECT (CINFO_GET_JPEGDEC (cinfo), "term_source");
+ return;
+}
+
+METHODDEF (void)
+ gst_jpeg_dec_my_output_message (j_common_ptr cinfo)
+{
+ return; /* do nothing */
+}
+
+METHODDEF (void)
+ gst_jpeg_dec_my_emit_message (j_common_ptr cinfo, int msg_level)
+{
+ /* GST_LOG_OBJECT (CINFO_GET_JPEGDEC (&cinfo), "msg_level=%d", msg_level); */
+ return;
+}
+
+METHODDEF (void)
+ gst_jpeg_dec_my_error_exit (j_common_ptr cinfo)
+{
+ struct GstJpegDecErrorMgr *err_mgr = (struct GstJpegDecErrorMgr *) cinfo->err;
+
+ (*cinfo->err->output_message) (cinfo);
+ longjmp (err_mgr->setjmp_buffer, 1);
+}
+
+static void
+gst_jpeg_dec_init (GstJpegDec * dec)
+{
+ GST_DEBUG ("initializing");
+
+ /* create the sink and src pads */
+ dec->sinkpad =
+ gst_pad_new_from_static_template (&gst_jpeg_dec_sink_pad_template,
+ "sink");
+ gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
+ gst_pad_set_setcaps_function (dec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_jpeg_dec_setcaps));
+ gst_pad_set_getcaps_function (dec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_jpeg_dec_getcaps));
+ gst_pad_set_chain_function (dec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_jpeg_dec_chain));
+ gst_pad_set_event_function (dec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_jpeg_dec_sink_event));
+
+ dec->srcpad =
+ gst_pad_new_from_static_template (&gst_jpeg_dec_src_pad_template, "src");
+ gst_pad_set_event_function (dec->srcpad,
+ GST_DEBUG_FUNCPTR (gst_jpeg_dec_src_event));
+ gst_pad_use_fixed_caps (dec->srcpad);
+ gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
+
+ /* setup jpeglib */
+ memset (&dec->cinfo, 0, sizeof (dec->cinfo));
+ memset (&dec->jerr, 0, sizeof (dec->jerr));
+ dec->cinfo.err = jpeg_std_error (&dec->jerr.pub);
+ dec->jerr.pub.output_message = gst_jpeg_dec_my_output_message;
+ dec->jerr.pub.emit_message = gst_jpeg_dec_my_emit_message;
+ dec->jerr.pub.error_exit = gst_jpeg_dec_my_error_exit;
+
+ jpeg_create_decompress (&dec->cinfo);
+
+ dec->cinfo.src = (struct jpeg_source_mgr *) &dec->jsrc;
+ dec->cinfo.src->init_source = gst_jpeg_dec_init_source;
+ dec->cinfo.src->fill_input_buffer = gst_jpeg_dec_fill_input_buffer;
+ dec->cinfo.src->skip_input_data = gst_jpeg_dec_skip_input_data;
+ dec->cinfo.src->resync_to_restart = gst_jpeg_dec_resync_to_restart;
+ dec->cinfo.src->term_source = gst_jpeg_dec_term_source;
+ dec->jsrc.dec = dec;
+
+ /* init properties */
+ dec->idct_method = JPEG_DEFAULT_IDCT_METHOD;
+ dec->max_errors = JPEG_DEFAULT_MAX_ERRORS;
+
+ dec->adapter = gst_adapter_new ();
+}
+
+static gboolean
+gst_jpeg_dec_ensure_header (GstJpegDec * dec)
+{
+ gint av;
+ gint offset;
+
+ av = gst_adapter_available (dec->adapter);
+ /* we expect at least 4 bytes, first of which start marker */
+ offset = gst_adapter_masked_scan_uint32 (dec->adapter, 0xffffff00, 0xffd8ff00,
+ 0, av);
+ if (G_UNLIKELY (offset < 0)) {
+ GST_DEBUG_OBJECT (dec, "No JPEG header in current buffer");
+ /* not found */
+ if (av > 4)
+ gst_adapter_flush (dec->adapter, av - 4);
+ return FALSE;
+ }
+
+ if (offset > 0) {
+ GST_LOG_OBJECT (dec, "Skipping %u bytes.", offset);
+ gst_adapter_flush (dec->adapter, offset);
+ }
+ GST_DEBUG_OBJECT (dec, "Found JPEG header");
+
+ return TRUE;
+}
+
+static inline gboolean
+gst_jpeg_dec_parse_tag_has_entropy_segment (guint8 tag)
+{
+ if (tag == 0xda || (tag >= 0xd0 && tag <= 0xd7))
+ return TRUE;
+ return FALSE;
+}
+
+/* returns image length in bytes if parsed successfully,
+ * otherwise 0 if more data needed,
+ * if < 0 the absolute value needs to be flushed */
+static gint
+gst_jpeg_dec_parse_image_data (GstJpegDec * dec)
+{
+ guint size;
+ gboolean resync;
+ GstAdapter *adapter = dec->adapter;
+ gint offset, noffset;
+
+ size = gst_adapter_available (adapter);
+
+ /* we expect at least 4 bytes, first of which start marker */
+ if (gst_adapter_masked_scan_uint32 (adapter, 0xffff0000, 0xffd80000, 0, 4))
+ return 0;
+
+ GST_DEBUG ("Parsing jpeg image data (%u bytes)", size);
+
+ GST_DEBUG ("Parse state: offset=%d, resync=%d, entropy len=%d",
+ dec->parse_offset, dec->parse_resync, dec->parse_entropy_len);
+
+ /* offset is 2 less than actual offset;
+ * - adapter needs at least 4 bytes for scanning,
+ * - start and end marker ensure at least that much
+ */
+ /* resume from state offset */
+ offset = dec->parse_offset;
+
+ while (1) {
+ guint frame_len;
+ guint32 value;
+
+ noffset =
+ gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00, 0x0000ff00,
+ offset, size - offset, &value);
+ /* lost sync if 0xff marker not where expected */
+ if ((resync = (noffset != offset))) {
+ GST_DEBUG ("Lost sync at 0x%08x, resyncing", offset + 2);
+ }
+ /* may have marker, but could have been resyncng */
+ resync = resync || dec->parse_resync;
+ /* Skip over extra 0xff */
+ while ((noffset >= 0) && ((value & 0xff) == 0xff)) {
+ noffset++;
+ noffset =
+ gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00, 0x0000ff00,
+ noffset, size - noffset, &value);
+ }
+ /* enough bytes left for marker? (we need 0xNN after the 0xff) */
+ if (noffset < 0) {
+ GST_DEBUG ("at end of input and no EOI marker found, need more data");
+ goto need_more_data;
+ }
+
+ /* now lock on the marker we found */
+ offset = noffset;
+ value = value & 0xff;
+ if (value == 0xd9) {
+ GST_DEBUG ("0x%08x: EOI marker", offset + 2);
+ /* clear parse state */
+ dec->parse_resync = FALSE;
+ dec->parse_offset = 0;
+ return (offset + 4);
+ } else if (value == 0xd8) {
+ /* Skip this frame if we found another SOI marker */
+ GST_DEBUG ("0x%08x: SOI marker before EOI, skipping", offset + 2);
+ dec->parse_resync = FALSE;
+ dec->parse_offset = 0;
+ return -(offset + 2);
+ }
+
+
+ if (value >= 0xd0 && value <= 0xd7)
+ frame_len = 0;
+ else {
+ /* peek tag and subsequent length */
+ if (offset + 2 + 4 > size)
+ goto need_more_data;
+ else
+ gst_adapter_masked_scan_uint32_peek (adapter, 0x0, 0x0, offset + 2, 4,
+ &frame_len);
+ frame_len = frame_len & 0xffff;
+ }
+ GST_DEBUG ("0x%08x: tag %02x, frame_len=%u", offset + 2, value, frame_len);
+ /* the frame length includes the 2 bytes for the length; here we want at
+ * least 2 more bytes at the end for an end marker */
+ if (offset + 2 + 2 + frame_len + 2 > size) {
+ goto need_more_data;
+ }
+
+ if (gst_jpeg_dec_parse_tag_has_entropy_segment (value)) {
+ guint eseglen = dec->parse_entropy_len;
+
+ GST_DEBUG ("0x%08x: finding entropy segment length", offset + 2);
+ noffset = offset + 2 + frame_len + dec->parse_entropy_len;
+ while (1) {
+ noffset = gst_adapter_masked_scan_uint32_peek (adapter, 0x0000ff00,
+ 0x0000ff00, noffset, size - noffset, &value);
+ if (noffset < 0) {
+ /* need more data */
+ dec->parse_entropy_len = size - offset - 4 - frame_len - 2;
+ goto need_more_data;
+ }
+ if ((value & 0xff) != 0x00) {
+ eseglen = noffset - offset - frame_len - 2;
+ break;
+ }
+ noffset++;
+ }
+ dec->parse_entropy_len = 0;
+ frame_len += eseglen;
+ GST_DEBUG ("entropy segment length=%u => frame_len=%u", eseglen,
+ frame_len);
+ }
+ if (resync) {
+ /* check if we will still be in sync if we interpret
+ * this as a sync point and skip this frame */
+ noffset = offset + frame_len + 2;
+ noffset = gst_adapter_masked_scan_uint32 (adapter, 0x0000ff00, 0x0000ff00,
+ noffset, 4);
+ if (noffset < 0) {
+ /* ignore and continue resyncing until we hit the end
+ * of our data or find a sync point that looks okay */
+ offset++;
+ continue;
+ }
+ GST_DEBUG ("found sync at 0x%x", offset + 2);
+ }
+
+ offset += frame_len + 2;
+ }
+
+ /* EXITS */
+need_more_data:
+ {
+ dec->parse_offset = offset;
+ dec->parse_resync = resync;
+ return 0;
+ }
+}
+
+/* shamelessly ripped from jpegutils.c in mjpegtools */
+static void
+add_huff_table (j_decompress_ptr dinfo,
+ JHUFF_TBL ** htblptr, const UINT8 * bits, const UINT8 * val)
+/* Define a Huffman table */
+{
+ int nsymbols, len;
+
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table ((j_common_ptr) dinfo);
+
+ g_assert (*htblptr);
+
+ /* Copy the number-of-symbols-of-each-code-length counts */
+ memcpy ((*htblptr)->bits, bits, sizeof ((*htblptr)->bits));
+
+ /* Validate the counts. We do this here mainly so we can copy the right
+ * number of symbols from the val[] array, without risking marching off
+ * the end of memory. jchuff.c will do a more thorough test later.
+ */
+ nsymbols = 0;
+ for (len = 1; len <= 16; len++)
+ nsymbols += bits[len];
+ if (nsymbols < 1 || nsymbols > 256)
+ g_error ("jpegutils.c: add_huff_table failed badly. ");
+
+ memcpy ((*htblptr)->huffval, val, nsymbols * sizeof (UINT8));
+}
+
+
+
+static void
+std_huff_tables (j_decompress_ptr dinfo)
+/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
+/* IMPORTANT: these are only valid for 8-bit data precision! */
+{
+ static const UINT8 bits_dc_luminance[17] =
+ { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
+ static const UINT8 val_dc_luminance[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+ static const UINT8 bits_dc_chrominance[17] =
+ { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
+ static const UINT8 val_dc_chrominance[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+ static const UINT8 bits_ac_luminance[17] =
+ { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
+ static const UINT8 val_ac_luminance[] =
+ { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+ };
+
+ static const UINT8 bits_ac_chrominance[17] =
+ { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
+ static const UINT8 val_ac_chrominance[] =
+ { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+ };
+
+ add_huff_table (dinfo, &dinfo->dc_huff_tbl_ptrs[0],
+ bits_dc_luminance, val_dc_luminance);
+ add_huff_table (dinfo, &dinfo->ac_huff_tbl_ptrs[0],
+ bits_ac_luminance, val_ac_luminance);
+ add_huff_table (dinfo, &dinfo->dc_huff_tbl_ptrs[1],
+ bits_dc_chrominance, val_dc_chrominance);
+ add_huff_table (dinfo, &dinfo->ac_huff_tbl_ptrs[1],
+ bits_ac_chrominance, val_ac_chrominance);
+}
+
+
+
+static void
+guarantee_huff_tables (j_decompress_ptr dinfo)
+{
+ if ((dinfo->dc_huff_tbl_ptrs[0] == NULL) &&
+ (dinfo->dc_huff_tbl_ptrs[1] == NULL) &&
+ (dinfo->ac_huff_tbl_ptrs[0] == NULL) &&
+ (dinfo->ac_huff_tbl_ptrs[1] == NULL)) {
+ GST_DEBUG ("Generating standard Huffman tables for this frame.");
+ std_huff_tables (dinfo);
+ }
+}
+
+static gboolean
+gst_jpeg_dec_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstStructure *s;
+ GstJpegDec *dec;
+ const GValue *framerate;
+
+ dec = GST_JPEG_DEC (GST_OBJECT_PARENT (pad));
+ s = gst_caps_get_structure (caps, 0);
+
+ if ((framerate = gst_structure_get_value (s, "framerate")) != NULL) {
+ dec->framerate_numerator = gst_value_get_fraction_numerator (framerate);
+ dec->framerate_denominator = gst_value_get_fraction_denominator (framerate);
+ dec->packetized = TRUE;
+ GST_DEBUG ("got framerate of %d/%d fps => packetized mode",
+ dec->framerate_numerator, dec->framerate_denominator);
+ }
+
+ /* do not extract width/height here. we do that in the chain
+ * function on a per-frame basis (including the line[] array
+ * setup) */
+
+ /* But we can take the framerate values and set them on the src pad */
+
+ return TRUE;
+}
+
+static GstCaps *
+gst_jpeg_dec_getcaps (GstPad * pad)
+{
+ GstJpegDec *dec;
+ GstCaps *caps;
+ GstPad *peer;
+
+ dec = GST_JPEG_DEC (GST_OBJECT_PARENT (pad));
+
+ if (GST_PAD_CAPS (pad))
+ return gst_caps_ref (GST_PAD_CAPS (pad));
+
+ peer = gst_pad_get_peer (dec->srcpad);
+
+ if (peer) {
+ GstCaps *peer_caps;
+ const GstCaps *templ_caps;
+ GstStructure *s;
+ guint i, n;
+
+ peer_caps = gst_pad_get_caps (peer);
+
+ /* Translate peercaps to image/jpeg */
+ peer_caps = gst_caps_make_writable (peer_caps);
+ n = gst_caps_get_size (peer_caps);
+ for (i = 0; i < n; i++) {
+ s = gst_caps_get_structure (peer_caps, i);
+
+ gst_structure_set_name (s, "image/jpeg");
+ }
+
+ templ_caps = gst_pad_get_pad_template_caps (pad);
+ caps = gst_caps_intersect_full (peer_caps, templ_caps,
+ GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (peer_caps);
+ gst_object_unref (peer);
+ } else {
+ caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+ }
+
+ return caps;
+}
+
+
+/* yuk */
+static void
+hresamplecpy1 (guint8 * dest, const guint8 * src, guint len)
+{
+ gint i;
+
+ for (i = 0; i < len; ++i) {
+ /* equivalent to: dest[i] = src[i << 1] */
+ *dest = *src;
+ ++dest;
+ ++src;
+ ++src;
+ }
+}
+
+static void
+gst_jpeg_dec_free_buffers (GstJpegDec * dec)
+{
+ gint i;
+
+ for (i = 0; i < 16; i++) {
+ g_free (dec->idr_y[i]);
+ g_free (dec->idr_u[i]);
+ g_free (dec->idr_v[i]);
+ dec->idr_y[i] = NULL;
+ dec->idr_u[i] = NULL;
+ dec->idr_v[i] = NULL;
+ }
+
+ dec->idr_width_allocated = 0;
+}
+
+static inline gboolean
+gst_jpeg_dec_ensure_buffers (GstJpegDec * dec, guint maxrowbytes)
+{
+ gint i;
+
+ if (G_LIKELY (dec->idr_width_allocated == maxrowbytes))
+ return TRUE;
+
+ /* FIXME: maybe just alloc one or three blocks altogether? */
+ for (i = 0; i < 16; i++) {
+ dec->idr_y[i] = g_try_realloc (dec->idr_y[i], maxrowbytes);
+ dec->idr_u[i] = g_try_realloc (dec->idr_u[i], maxrowbytes);
+ dec->idr_v[i] = g_try_realloc (dec->idr_v[i], maxrowbytes);
+
+ if (G_UNLIKELY (!dec->idr_y[i] || !dec->idr_u[i] || !dec->idr_v[i])) {
+ GST_WARNING_OBJECT (dec, "out of memory, i=%d, bytes=%u", i, maxrowbytes);
+ return FALSE;
+ }
+ }
+
+ dec->idr_width_allocated = maxrowbytes;
+ GST_LOG_OBJECT (dec, "allocated temp memory, %u bytes/row", maxrowbytes);
+ return TRUE;
+}
+
+static void
+gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, guchar * base[1],
+ guint width, guint height, guint pstride, guint rstride)
+{
+ guchar *rows[16];
+ guchar **scanarray[1] = { rows };
+ gint i, j, k;
+ gint lines;
+
+ GST_DEBUG_OBJECT (dec, "indirect decoding of grayscale");
+
+ if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
+ return;
+
+ memcpy (rows, dec->idr_y, 16 * sizeof (gpointer));
+
+ i = 0;
+ while (i < height) {
+ lines = jpeg_read_raw_data (&dec->cinfo, scanarray, DCTSIZE);
+ if (G_LIKELY (lines > 0)) {
+ for (j = 0; (j < DCTSIZE) && (i < height); j++, i++) {
+ gint p;
+
+ p = 0;
+ for (k = 0; k < width; k++) {
+ base[0][p] = rows[j][k];
+ p += pstride;
+ }
+ base[0] += rstride;
+ }
+ } else {
+ GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
+ }
+ }
+}
+
+static void
+gst_jpeg_dec_decode_rgb (GstJpegDec * dec, guchar * base[3],
+ guint width, guint height, guint pstride, guint rstride)
+{
+ guchar *r_rows[16], *g_rows[16], *b_rows[16];
+ guchar **scanarray[3] = { r_rows, g_rows, b_rows };
+ gint i, j, k;
+ gint lines;
+
+ GST_DEBUG_OBJECT (dec, "indirect decoding of RGB");
+
+ if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
+ return;
+
+ memcpy (r_rows, dec->idr_y, 16 * sizeof (gpointer));
+ memcpy (g_rows, dec->idr_u, 16 * sizeof (gpointer));
+ memcpy (b_rows, dec->idr_v, 16 * sizeof (gpointer));
+
+ i = 0;
+ while (i < height) {
+ lines = jpeg_read_raw_data (&dec->cinfo, scanarray, DCTSIZE);
+ if (G_LIKELY (lines > 0)) {
+ for (j = 0; (j < DCTSIZE) && (i < height); j++, i++) {
+ gint p;
+
+ p = 0;
+ for (k = 0; k < width; k++) {
+ base[0][p] = r_rows[j][k];
+ base[1][p] = g_rows[j][k];
+ base[2][p] = b_rows[j][k];
+ p += pstride;
+ }
+ base[0] += rstride;
+ base[1] += rstride;
+ base[2] += rstride;
+ }
+ } else {
+ GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
+ }
+ }
+}
+
+static void
+gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3],
+ guchar * last[3], guint width, guint height, gint r_v, gint r_h, gint comp)
+{
+ guchar *y_rows[16], *u_rows[16], *v_rows[16];
+ guchar **scanarray[3] = { y_rows, u_rows, v_rows };
+ gint i, j, k;
+ gint lines;
+
+ GST_DEBUG_OBJECT (dec,
+ "unadvantageous width or r_h, taking slow route involving memcpy");
+
+ if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
+ return;
+
+ memcpy (y_rows, dec->idr_y, 16 * sizeof (gpointer));
+ memcpy (u_rows, dec->idr_u, 16 * sizeof (gpointer));
+ memcpy (v_rows, dec->idr_v, 16 * sizeof (gpointer));
+
+ /* fill chroma components for grayscale */
+ if (comp == 1) {
+ GST_DEBUG_OBJECT (dec, "grayscale, filling chroma");
+ for (i = 0; i < 16; i++) {
+ memset (u_rows[i], GST_ROUND_UP_32 (width), 0x80);
+ memset (v_rows[i], GST_ROUND_UP_32 (width), 0x80);
+ }
+ }
+
+ for (i = 0; i < height; i += r_v * DCTSIZE) {
+ lines = jpeg_read_raw_data (&dec->cinfo, scanarray, r_v * DCTSIZE);
+ if (G_LIKELY (lines > 0)) {
+ for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) {
+ if (G_LIKELY (base[0] <= last[0])) {
+ memcpy (base[0], y_rows[j], I420_Y_ROWSTRIDE (width));
+ base[0] += I420_Y_ROWSTRIDE (width);
+ }
+ if (r_v == 2) {
+ if (G_LIKELY (base[0] <= last[0])) {
+ memcpy (base[0], y_rows[j + 1], I420_Y_ROWSTRIDE (width));
+ base[0] += I420_Y_ROWSTRIDE (width);
+ }
+ }
+ if (G_LIKELY (base[1] <= last[1] && base[2] <= last[2])) {
+ if (r_h == 2) {
+ memcpy (base[1], u_rows[k], I420_U_ROWSTRIDE (width));
+ memcpy (base[2], v_rows[k], I420_V_ROWSTRIDE (width));
+ } else if (r_h == 1) {
+ hresamplecpy1 (base[1], u_rows[k], I420_U_ROWSTRIDE (width));
+ hresamplecpy1 (base[2], v_rows[k], I420_V_ROWSTRIDE (width));
+ } else {
+ /* FIXME: implement (at least we avoid crashing by doing nothing) */
+ }
+ }
+
+ if (r_v == 2 || (k & 1) != 0) {
+ base[1] += I420_U_ROWSTRIDE (width);
+ base[2] += I420_V_ROWSTRIDE (width);
+ }
+ }
+ } else {
+ GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
+ }
+ }
+}
+
+#ifndef GST_DISABLE_GST_DEBUG
+static inline void
+dump_lines (guchar * base[3], guchar ** line[3], int v_samp0, int width)
+{
+ int j;
+
+ for (j = 0; j < (v_samp0 * DCTSIZE); ++j) {
+ GST_LOG ("[%02d] %5d %5d %5d", j,
+ (line[0][j] >= base[0]) ?
+ (int) (line[0][j] - base[0]) / I420_Y_ROWSTRIDE (width) : -1,
+ (line[1][j] >= base[1]) ?
+ (int) (line[1][j] - base[1]) / I420_U_ROWSTRIDE (width) : -1,
+ (line[2][j] >= base[2]) ?
+ (int) (line[2][j] - base[2]) / I420_V_ROWSTRIDE (width) : -1);
+ }
+}
+#endif
+
+static GstFlowReturn
+gst_jpeg_dec_decode_direct (GstJpegDec * dec, guchar * base[3],
+ guchar * last[3], guint width, guint height)
+{
+ guchar **line[3]; /* the jpeg line buffer */
+ guchar *y[4 * DCTSIZE] = { NULL, }; /* alloc enough for the lines */
+ guchar *u[4 * DCTSIZE] = { NULL, }; /* r_v will be <4 */
+ guchar *v[4 * DCTSIZE] = { NULL, };
+ gint i, j;
+ gint lines, v_samp[3];
+
+ line[0] = y;
+ line[1] = u;
+ line[2] = v;
+
+ v_samp[0] = dec->cinfo.comp_info[0].v_samp_factor;
+ v_samp[1] = dec->cinfo.comp_info[1].v_samp_factor;
+ v_samp[2] = dec->cinfo.comp_info[2].v_samp_factor;
+
+ if (G_UNLIKELY (v_samp[0] > 2 || v_samp[1] > 2 || v_samp[2] > 2))
+ goto format_not_supported;
+
+ /* let jpeglib decode directly into our final buffer */
+ GST_DEBUG_OBJECT (dec, "decoding directly into output buffer");
+
+ for (i = 0; i < height; i += v_samp[0] * DCTSIZE) {
+ for (j = 0; j < (v_samp[0] * DCTSIZE); ++j) {
+ /* Y */
+ line[0][j] = base[0] + (i + j) * I420_Y_ROWSTRIDE (width);
+ if (G_UNLIKELY (line[0][j] > last[0]))
+ line[0][j] = last[0];
+ /* U */
+ if (v_samp[1] == v_samp[0]) {
+ line[1][j] = base[1] + ((i + j) / 2) * I420_U_ROWSTRIDE (width);
+ } else if (j < (v_samp[1] * DCTSIZE)) {
+ line[1][j] = base[1] + ((i / 2) + j) * I420_U_ROWSTRIDE (width);
+ }
+ if (G_UNLIKELY (line[1][j] > last[1]))
+ line[1][j] = last[1];
+ /* V */
+ if (v_samp[2] == v_samp[0]) {
+ line[2][j] = base[2] + ((i + j) / 2) * I420_V_ROWSTRIDE (width);
+ } else if (j < (v_samp[2] * DCTSIZE)) {
+ line[2][j] = base[2] + ((i / 2) + j) * I420_V_ROWSTRIDE (width);
+ }
+ if (G_UNLIKELY (line[2][j] > last[2]))
+ line[2][j] = last[2];
+ }
+
+ /* dump_lines (base, line, v_samp[0], width); */
+
+ lines = jpeg_read_raw_data (&dec->cinfo, line, v_samp[0] * DCTSIZE);
+ if (G_UNLIKELY (!lines)) {
+ GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
+ }
+ }
+ return GST_FLOW_OK;
+
+format_not_supported:
+ {
+ gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
+ "Unsupported subsampling schema: v_samp factors: %u %u %u",
+ v_samp[0], v_samp[1], v_samp[2]);
+ return GST_FLOW_ERROR;
+ }
+}
+
+static void
+gst_jpeg_dec_update_qos (GstJpegDec * dec, gdouble proportion,
+ GstClockTimeDiff diff, GstClockTime ts)
+{
+ GST_OBJECT_LOCK (dec);
+ dec->proportion = proportion;
+ if (G_LIKELY (ts != GST_CLOCK_TIME_NONE)) {
+ if (G_UNLIKELY (diff > 0))
+ dec->earliest_time = ts + 2 * diff + dec->qos_duration;
+ else
+ dec->earliest_time = ts + diff;
+ } else {
+ dec->earliest_time = GST_CLOCK_TIME_NONE;
+ }
+ GST_OBJECT_UNLOCK (dec);
+}
+
+static void
+gst_jpeg_dec_reset_qos (GstJpegDec * dec)
+{
+ gst_jpeg_dec_update_qos (dec, 0.5, 0, GST_CLOCK_TIME_NONE);
+}
+
+static void
+gst_jpeg_dec_read_qos (GstJpegDec * dec, gdouble * proportion,
+ GstClockTime * time)
+{
+ GST_OBJECT_LOCK (dec);
+ *proportion = dec->proportion;
+ *time = dec->earliest_time;
+ GST_OBJECT_UNLOCK (dec);
+}
+
+/* Perform qos calculations before decoding the next frame. Returns TRUE if the
+ * frame should be decoded, FALSE if the frame can be dropped entirely */
+static gboolean
+gst_jpeg_dec_do_qos (GstJpegDec * dec, GstClockTime timestamp)
+{
+ GstClockTime qostime, earliest_time;
+ gdouble proportion;
+
+ /* no timestamp, can't do QoS => decode frame */
+ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
+ GST_LOG_OBJECT (dec, "invalid timestamp, can't do QoS, decode frame");
+ return TRUE;
+ }
+
+ /* get latest QoS observation values */
+ gst_jpeg_dec_read_qos (dec, &proportion, &earliest_time);
+
+ /* skip qos if we have no observation (yet) => decode frame */
+ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
+ GST_LOG_OBJECT (dec, "no observation yet, decode frame");
+ return TRUE;
+ }
+
+ /* qos is done on running time */
+ qostime = gst_segment_to_running_time (&dec->segment, GST_FORMAT_TIME,
+ timestamp);
+
+ /* see how our next timestamp relates to the latest qos timestamp */
+ GST_LOG_OBJECT (dec, "qostime %" GST_TIME_FORMAT ", earliest %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
+
+ if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
+ GST_DEBUG_OBJECT (dec, "we are late, drop frame");
+ return FALSE;
+ }
+
+ GST_LOG_OBJECT (dec, "decode frame");
+ return TRUE;
+}
+
+static void
+gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc)
+{
+ GstCaps *caps;
+ GstVideoFormat format;
+
+ if (G_UNLIKELY (width == dec->caps_width && height == dec->caps_height &&
+ dec->framerate_numerator == dec->caps_framerate_numerator &&
+ dec->framerate_denominator == dec->caps_framerate_denominator &&
+ clrspc == dec->clrspc))
+ return;
+
+ /* framerate == 0/1 is a still frame */
+ if (dec->framerate_denominator == 0) {
+ dec->framerate_numerator = 0;
+ dec->framerate_denominator = 1;
+ }
+
+ /* calculate or assume an average frame duration for QoS purposes */
+ GST_OBJECT_LOCK (dec);
+ if (dec->framerate_numerator != 0) {
+ dec->qos_duration = gst_util_uint64_scale (GST_SECOND,
+ dec->framerate_denominator, dec->framerate_numerator);
+ } else {
+ /* if not set just use 25fps */
+ dec->qos_duration = gst_util_uint64_scale (GST_SECOND, 1, 25);
+ }
+ GST_OBJECT_UNLOCK (dec);
+
+ if (dec->cinfo.jpeg_color_space == JCS_RGB) {
+ gint i;
+ GstCaps *allowed_caps;
+
+ GST_DEBUG_OBJECT (dec, "selecting RGB format");
+ /* retrieve allowed caps, and find the first one that reasonably maps
+ * to the parameters of the colourspace */
+ caps = gst_pad_get_allowed_caps (dec->srcpad);
+ if (!caps) {
+ GST_DEBUG_OBJECT (dec, "... but no peer, using template caps");
+ /* need to copy because get_allowed_caps returns a ref,
+ * and get_pad_template_caps doesn't */
+ caps = gst_caps_copy (gst_pad_get_pad_template_caps (dec->srcpad));
+ }
+ /* avoid lists of fourcc, etc */
+ allowed_caps = gst_caps_normalize (caps);
+ gst_caps_unref (caps);
+ caps = NULL;
+ GST_LOG_OBJECT (dec, "allowed source caps %" GST_PTR_FORMAT, allowed_caps);
+
+ for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
+ if (caps)
+ gst_caps_unref (caps);
+ caps = gst_caps_copy_nth (allowed_caps, i);
+ /* sigh, ds and _parse_caps need fixed caps for parsing, fixate */
+ gst_pad_fixate_caps (dec->srcpad, caps);
+ GST_LOG_OBJECT (dec, "checking caps %" GST_PTR_FORMAT, caps);
+ if (!gst_video_format_parse_caps (caps, &format, NULL, NULL))
+ continue;
+ /* we'll settle for the first (preferred) downstream rgb format */
+ if (gst_video_format_is_rgb (format))
+ break;
+ /* default fall-back */
+ format = GST_VIDEO_FORMAT_RGB;
+ }
+ if (caps)
+ gst_caps_unref (caps);
+ gst_caps_unref (allowed_caps);
+ caps = gst_video_format_new_caps (format, width, height,
+ dec->framerate_numerator, dec->framerate_denominator, 1, 1);
+ dec->outsize = gst_video_format_get_size (format, width, height);
+ /* some format info */
+ dec->offset[0] =
+ gst_video_format_get_component_offset (format, 0, width, height);
+ dec->offset[1] =
+ gst_video_format_get_component_offset (format, 1, width, height);
+ dec->offset[2] =
+ gst_video_format_get_component_offset (format, 2, width, height);
+ /* equal for all components */
+ dec->stride = gst_video_format_get_row_stride (format, 0, width);
+ dec->inc = gst_video_format_get_pixel_stride (format, 0);
+ } else if (dec->cinfo.jpeg_color_space == JCS_GRAYSCALE) {
+ /* TODO is anything else then 8bit supported in jpeg? */
+ format = GST_VIDEO_FORMAT_GRAY8;
+ caps = gst_video_format_new_caps (format, width, height,
+ dec->framerate_numerator, dec->framerate_denominator, 1, 1);
+ dec->outsize = gst_video_format_get_size (format, width, height);
+ dec->offset[0] =
+ gst_video_format_get_component_offset (format, 0, width, height);
+ dec->stride = gst_video_format_get_row_stride (format, 0, width);
+ dec->inc = gst_video_format_get_pixel_stride (format, 0);
+ } else {
+ /* go for plain and simple I420 */
+ /* TODO other YUV cases ? */
+ caps = gst_caps_new_simple ("video/x-raw-yuv",
+ "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
+ "width", G_TYPE_INT, width, "height", G_TYPE_INT, height,
+ "framerate", GST_TYPE_FRACTION, dec->framerate_numerator,
+ dec->framerate_denominator, NULL);
+ dec->outsize = I420_SIZE (width, height);
+ }
+
+ GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps);
+ GST_DEBUG_OBJECT (dec, "max_v_samp_factor=%d", dec->cinfo.max_v_samp_factor);
+ GST_DEBUG_OBJECT (dec, "max_h_samp_factor=%d", dec->cinfo.max_h_samp_factor);
+
+ gst_pad_set_caps (dec->srcpad, caps);
+ gst_caps_unref (caps);
+
+ dec->caps_width = width;
+ dec->caps_height = height;
+ dec->caps_framerate_numerator = dec->framerate_numerator;
+ dec->caps_framerate_denominator = dec->framerate_denominator;
+}
+
+static GstFlowReturn
+gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstJpegDec *dec;
+ GstBuffer *outbuf = NULL;
+#ifndef GST_DISABLE_GST_DEBUG
+ guchar *data;
+#endif
+ guchar *outdata;
+ guchar *base[3], *last[3];
+ gint img_len;
+ guint outsize;
+ gint width, height;
+ gint r_h, r_v;
+ guint code, hdr_ok;
+ GstClockTime timestamp, duration;
+
+ dec = GST_JPEG_DEC (GST_PAD_PARENT (pad));
+
+ timestamp = GST_BUFFER_TIMESTAMP (buf);
+ duration = GST_BUFFER_DURATION (buf);
+
+ if (GST_CLOCK_TIME_IS_VALID (timestamp))
+ dec->next_ts = timestamp;
+
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ GST_DEBUG_OBJECT (dec, "buffer has DISCONT flag set");
+ dec->discont = TRUE;
+ if (!dec->packetized && gst_adapter_available (dec->adapter)) {
+ GST_WARNING_OBJECT (dec, "DISCONT buffer in non-packetized mode, bad");
+ gst_adapter_clear (dec->adapter);
+ }
+ }
+
+ gst_adapter_push (dec->adapter, buf);
+ buf = NULL;
+
+ /* If we are non-packetized and know the total incoming size in bytes,
+ * just wait until we have enough before doing any processing. */
+
+ if (!dec->packetized && (dec->segment.format == GST_FORMAT_BYTES) &&
+ (dec->segment.stop != -1) &&
+ (gst_adapter_available (dec->adapter) < dec->segment.stop)) {
+ /* We assume that non-packetized input in bytes is *one* single jpeg image */
+ GST_DEBUG ("Non-packetized mode. Got %d bytes, need %" G_GINT64_FORMAT,
+ gst_adapter_available (dec->adapter), dec->segment.stop);
+ goto need_more_data;
+ }
+
+again:
+ if (!gst_jpeg_dec_ensure_header (dec))
+ goto need_more_data;
+
+ /* If we know that each input buffer contains data
+ * for a whole jpeg image (e.g. MJPEG streams), just
+ * do some sanity checking instead of parsing all of
+ * the jpeg data */
+ if (dec->packetized) {
+ img_len = gst_adapter_available (dec->adapter);
+ } else {
+ /* Parse jpeg image to handle jpeg input that
+ * is not aligned to buffer boundaries */
+ img_len = gst_jpeg_dec_parse_image_data (dec);
+
+ if (img_len == 0) {
+ goto need_more_data;
+ } else if (img_len < 0) {
+ gst_adapter_flush (dec->adapter, -img_len);
+ goto again;
+ }
+ }
+
+ dec->rem_img_len = img_len;
+
+ GST_LOG_OBJECT (dec, "image size = %u", img_len);
+
+ /* QoS: if we're too late anyway, skip decoding */
+ if (dec->packetized && !gst_jpeg_dec_do_qos (dec, timestamp))
+ goto skip_decoding;
+
+#ifndef GST_DISABLE_GST_DEBUG
+ data = (guint8 *) gst_adapter_peek (dec->adapter, 4);
+ GST_LOG_OBJECT (dec, "reading header %02x %02x %02x %02x", data[0], data[1],
+ data[2], data[3]);
+#endif
+
+ gst_jpeg_dec_fill_input_buffer (&dec->cinfo);
+
+ if (setjmp (dec->jerr.setjmp_buffer)) {
+ code = dec->jerr.pub.msg_code;
+
+ if (code == JERR_INPUT_EOF) {
+ GST_DEBUG ("jpeg input EOF error, we probably need more data");
+ goto need_more_data;
+ }
+ goto decode_error;
+ }
+
+ /* read header */
+ hdr_ok = jpeg_read_header (&dec->cinfo, TRUE);
+ if (G_UNLIKELY (hdr_ok != JPEG_HEADER_OK)) {
+ GST_WARNING_OBJECT (dec, "reading the header failed, %d", hdr_ok);
+ }
+
+ GST_LOG_OBJECT (dec, "num_components=%d", dec->cinfo.num_components);
+ GST_LOG_OBJECT (dec, "jpeg_color_space=%d", dec->cinfo.jpeg_color_space);
+
+ if (!dec->cinfo.num_components || !dec->cinfo.comp_info)
+ goto components_not_supported;
+
+ r_h = dec->cinfo.comp_info[0].h_samp_factor;
+ r_v = dec->cinfo.comp_info[0].v_samp_factor;
+
+ GST_LOG_OBJECT (dec, "r_h = %d, r_v = %d", r_h, r_v);
+
+ if (dec->cinfo.num_components > 3)
+ goto components_not_supported;
+
+ /* verify color space expectation to avoid going *boom* or bogus output */
+ if (dec->cinfo.jpeg_color_space != JCS_YCbCr &&
+ dec->cinfo.jpeg_color_space != JCS_GRAYSCALE &&
+ dec->cinfo.jpeg_color_space != JCS_RGB)
+ goto unsupported_colorspace;
+
+#ifndef GST_DISABLE_GST_DEBUG
+ {
+ gint i;
+
+ for (i = 0; i < dec->cinfo.num_components; ++i) {
+ GST_LOG_OBJECT (dec, "[%d] h_samp_factor=%d, v_samp_factor=%d, cid=%d",
+ i, dec->cinfo.comp_info[i].h_samp_factor,
+ dec->cinfo.comp_info[i].v_samp_factor,
+ dec->cinfo.comp_info[i].component_id);
+ }
+ }
+#endif
+
+ /* prepare for raw output */
+ dec->cinfo.do_fancy_upsampling = FALSE;
+ dec->cinfo.do_block_smoothing = FALSE;
+ dec->cinfo.out_color_space = dec->cinfo.jpeg_color_space;
+ dec->cinfo.dct_method = dec->idct_method;
+ dec->cinfo.raw_data_out = TRUE;
+
+ GST_LOG_OBJECT (dec, "starting decompress");
+ guarantee_huff_tables (&dec->cinfo);
+ if (!jpeg_start_decompress (&dec->cinfo)) {
+ GST_WARNING_OBJECT (dec, "failed to start decompression cycle");
+ }
+
+ /* sanity checks to get safe and reasonable output */
+ switch (dec->cinfo.jpeg_color_space) {
+ case JCS_GRAYSCALE:
+ if (dec->cinfo.num_components != 1)
+ goto invalid_yuvrgbgrayscale;
+ break;
+ case JCS_RGB:
+ if (dec->cinfo.num_components != 3 || dec->cinfo.max_v_samp_factor > 1 ||
+ dec->cinfo.max_h_samp_factor > 1)
+ goto invalid_yuvrgbgrayscale;
+ break;
+ case JCS_YCbCr:
+ if (dec->cinfo.num_components != 3 ||
+ r_v > 2 || r_v < dec->cinfo.comp_info[0].v_samp_factor ||
+ r_v < dec->cinfo.comp_info[1].v_samp_factor ||
+ r_h < dec->cinfo.comp_info[0].h_samp_factor ||
+ r_h < dec->cinfo.comp_info[1].h_samp_factor)
+ goto invalid_yuvrgbgrayscale;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ width = dec->cinfo.output_width;
+ height = dec->cinfo.output_height;
+
+ if (G_UNLIKELY (width < MIN_WIDTH || width > MAX_WIDTH ||
+ height < MIN_HEIGHT || height > MAX_HEIGHT))
+ goto wrong_size;
+
+ gst_jpeg_dec_negotiate (dec, width, height, dec->cinfo.jpeg_color_space);
+
+ ret = gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
+ dec->outsize, GST_PAD_CAPS (dec->srcpad), &outbuf);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto alloc_failed;
+
+ outdata = GST_BUFFER_DATA (outbuf);
+ outsize = GST_BUFFER_SIZE (outbuf);
+
+ GST_LOG_OBJECT (dec, "width %d, height %d, buffer size %d, required size %d",
+ width, height, outsize, dec->outsize);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = dec->next_ts;
+
+ if (dec->packetized && GST_CLOCK_TIME_IS_VALID (dec->next_ts)) {
+ if (GST_CLOCK_TIME_IS_VALID (duration)) {
+ /* use duration from incoming buffer for outgoing buffer */
+ dec->next_ts += duration;
+ } else if (dec->framerate_numerator != 0) {
+ duration = gst_util_uint64_scale (GST_SECOND,
+ dec->framerate_denominator, dec->framerate_numerator);
+ dec->next_ts += duration;
+ } else {
+ duration = GST_CLOCK_TIME_NONE;
+ dec->next_ts = GST_CLOCK_TIME_NONE;
+ }
+ } else {
+ duration = GST_CLOCK_TIME_NONE;
+ dec->next_ts = GST_CLOCK_TIME_NONE;
+ }
+ GST_BUFFER_DURATION (outbuf) = duration;
+
+ if (dec->cinfo.jpeg_color_space == JCS_RGB) {
+ base[0] = outdata + dec->offset[0];
+ base[1] = outdata + dec->offset[1];
+ base[2] = outdata + dec->offset[2];
+ gst_jpeg_dec_decode_rgb (dec, base, width, height, dec->inc, dec->stride);
+ } else if (dec->cinfo.jpeg_color_space == JCS_GRAYSCALE) {
+ base[0] = outdata + dec->offset[0];
+ gst_jpeg_dec_decode_grayscale (dec, base, width, height, dec->inc,
+ dec->stride);
+ } else {
+ /* mind the swap, jpeglib outputs blue chroma first
+ * ensonic: I see no swap?
+ */
+ base[0] = outdata + I420_Y_OFFSET (width, height);
+ base[1] = outdata + I420_U_OFFSET (width, height);
+ base[2] = outdata + I420_V_OFFSET (width, height);
+
+ /* make sure we don't make jpeglib write beyond our buffer,
+ * which might happen if (height % (r_v*DCTSIZE)) != 0 */
+ last[0] = base[0] + (I420_Y_ROWSTRIDE (width) * (height - 1));
+ last[1] =
+ base[1] + (I420_U_ROWSTRIDE (width) * ((GST_ROUND_UP_2 (height) / 2) -
+ 1));
+ last[2] =
+ base[2] + (I420_V_ROWSTRIDE (width) * ((GST_ROUND_UP_2 (height) / 2) -
+ 1));
+
+ GST_LOG_OBJECT (dec, "decompressing (reqired scanline buffer height = %u)",
+ dec->cinfo.rec_outbuf_height);
+
+ /* For some widths jpeglib requires more horizontal padding than I420
+ * provides. In those cases we need to decode into separate buffers and then
+ * copy over the data into our final picture buffer, otherwise jpeglib might
+ * write over the end of a line into the beginning of the next line,
+ * resulting in blocky artifacts on the left side of the picture. */
+ if (G_UNLIKELY (width % (dec->cinfo.max_h_samp_factor * DCTSIZE) != 0
+ || dec->cinfo.comp_info[0].h_samp_factor != 2
+ || dec->cinfo.comp_info[1].h_samp_factor != 1
+ || dec->cinfo.comp_info[2].h_samp_factor != 1)) {
+ GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec,
+ "indirect decoding using extra buffer copy");
+ gst_jpeg_dec_decode_indirect (dec, base, last, width, height, r_v, r_h,
+ dec->cinfo.num_components);
+ } else {
+ ret = gst_jpeg_dec_decode_direct (dec, base, last, width, height);
+
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto decode_direct_failed;
+ }
+ }
+
+ GST_LOG_OBJECT (dec, "decompressing finished");
+ jpeg_finish_decompress (&dec->cinfo);
+
+ /* Clipping */
+ if (dec->segment.format == GST_FORMAT_TIME) {
+ gint64 start, stop, clip_start, clip_stop;
+
+ GST_LOG_OBJECT (dec, "Attempting clipping");
+
+ start = GST_BUFFER_TIMESTAMP (outbuf);
+ if (GST_BUFFER_DURATION (outbuf) == GST_CLOCK_TIME_NONE)
+ stop = start;
+ else
+ stop = start + GST_BUFFER_DURATION (outbuf);
+
+ if (gst_segment_clip (&dec->segment, GST_FORMAT_TIME,
+ start, stop, &clip_start, &clip_stop)) {
+ GST_LOG_OBJECT (dec, "Clipping start to %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (clip_start));
+ GST_BUFFER_TIMESTAMP (outbuf) = clip_start;
+ if (GST_BUFFER_DURATION (outbuf) != GST_CLOCK_TIME_NONE) {
+ GST_LOG_OBJECT (dec, "Clipping duration to %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (clip_stop - clip_start));
+ GST_BUFFER_DURATION (outbuf) = clip_stop - clip_start;
+ }
+ } else
+ goto drop_buffer;
+ }
+
+ /* reset error count on successful decode */
+ dec->error_count = 0;
+
+ ++dec->good_count;
+
+ GST_LOG_OBJECT (dec, "pushing buffer (ts=%" GST_TIME_FORMAT ", dur=%"
+ GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+ GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
+
+ ret = gst_pad_push (dec->srcpad, outbuf);
+
+skip_decoding:
+done:
+ gst_adapter_flush (dec->adapter, dec->rem_img_len);
+
+exit:
+
+ if (G_UNLIKELY (ret == GST_FLOW_ERROR)) {
+ jpeg_abort_decompress (&dec->cinfo);
+ ret = gst_jpeg_dec_post_error_or_warning (dec);
+ }
+
+ return ret;
+
+ /* special cases */
+need_more_data:
+ {
+ GST_LOG_OBJECT (dec, "we need more data");
+ if (outbuf) {
+ gst_buffer_unref (outbuf);
+ outbuf = NULL;
+ }
+ ret = GST_FLOW_OK;
+ goto exit;
+ }
+ /* ERRORS */
+wrong_size:
+ {
+ gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
+ "Picture is too small or too big (%ux%u)", width, height);
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+decode_error:
+ {
+ gchar err_msg[JMSG_LENGTH_MAX];
+
+ dec->jerr.pub.format_message ((j_common_ptr) (&dec->cinfo), err_msg);
+
+ gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
+ "Decode error #%u: %s", code, err_msg);
+
+ if (outbuf) {
+ gst_buffer_unref (outbuf);
+ outbuf = NULL;
+ }
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+decode_direct_failed:
+ {
+ /* already posted an error message */
+ jpeg_abort_decompress (&dec->cinfo);
+ gst_buffer_replace (&outbuf, NULL);
+ goto done;
+ }
+alloc_failed:
+ {
+ const gchar *reason;
+
+ reason = gst_flow_get_name (ret);
+
+ GST_DEBUG_OBJECT (dec, "failed to alloc buffer, reason %s", reason);
+ /* Reset for next time */
+ jpeg_abort_decompress (&dec->cinfo);
+ if (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_WRONG_STATE &&
+ ret != GST_FLOW_NOT_LINKED) {
+ gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
+ "Buffer allocation failed, reason: %s", reason);
+ }
+ goto exit;
+ }
+drop_buffer:
+ {
+ GST_WARNING_OBJECT (dec, "Outgoing buffer is outside configured segment");
+ gst_buffer_unref (outbuf);
+ ret = GST_FLOW_OK;
+ goto exit;
+ }
+components_not_supported:
+ {
+ gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
+ "number of components not supported: %d (max 3)",
+ dec->cinfo.num_components);
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+unsupported_colorspace:
+ {
+ gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
+ "Picture has unknown or unsupported colourspace");
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+invalid_yuvrgbgrayscale:
+ {
+ gst_jpeg_dec_set_error (dec, GST_FUNCTION, __LINE__,
+ "Picture is corrupt or unhandled YUV/RGB/grayscale layout");
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+}
+
+static gboolean
+gst_jpeg_dec_src_event (GstPad * pad, GstEvent * event)
+{
+ GstJpegDec *dec;
+ gboolean res;
+
+ dec = GST_JPEG_DEC (gst_pad_get_parent (pad));
+ if (G_UNLIKELY (dec == NULL)) {
+ gst_event_unref (event);
+ return FALSE;
+ }
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_QOS:{
+ GstClockTimeDiff diff;
+ GstClockTime timestamp;
+ gdouble proportion;
+
+ gst_event_parse_qos (event, &proportion, &diff, &timestamp);
+ gst_jpeg_dec_update_qos (dec, proportion, diff, timestamp);
+ break;
+ }
+ default:
+ break;
+ }
+
+ res = gst_pad_push_event (dec->sinkpad, event);
+
+ gst_object_unref (dec);
+ return res;
+}
+
+static gboolean
+gst_jpeg_dec_sink_event (GstPad * pad, GstEvent * event)
+{
+ gboolean ret = TRUE;
+ GstJpegDec *dec = GST_JPEG_DEC (GST_OBJECT_PARENT (pad));
+
+ GST_DEBUG_OBJECT (dec, "event : %s", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ GST_DEBUG_OBJECT (dec, "Aborting decompress");
+ jpeg_abort_decompress (&dec->cinfo);
+ gst_segment_init (&dec->segment, GST_FORMAT_UNDEFINED);
+ gst_adapter_clear (dec->adapter);
+ g_free (dec->cur_buf);
+ dec->cur_buf = NULL;
+ dec->parse_offset = 0;
+ dec->parse_entropy_len = 0;
+ dec->parse_resync = FALSE;
+ gst_jpeg_dec_reset_qos (dec);
+ break;
+ case GST_EVENT_NEWSEGMENT:{
+ gboolean update;
+ gdouble rate, applied_rate;
+ GstFormat format;
+ gint64 start, stop, position;
+
+ gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
+ &format, &start, &stop, &position);
+
+ GST_DEBUG_OBJECT (dec, "Got NEWSEGMENT [%" GST_TIME_FORMAT
+ " - %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "]",
+ GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
+ GST_TIME_ARGS (position));
+
+ gst_segment_set_newsegment_full (&dec->segment, update, rate,
+ applied_rate, format, start, stop, position);
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ ret = gst_pad_push_event (dec->srcpad, event);
+
+ return ret;
+}
+
+static void
+gst_jpeg_dec_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstJpegDec *dec;
+
+ dec = GST_JPEG_DEC (object);
+
+ switch (prop_id) {
+ case PROP_IDCT_METHOD:
+ dec->idct_method = g_value_get_enum (value);
+ break;
+ case PROP_MAX_ERRORS:
+ g_atomic_int_set (&dec->max_errors, g_value_get_int (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_jpeg_dec_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstJpegDec *dec;
+
+ dec = GST_JPEG_DEC (object);
+
+ switch (prop_id) {
+ case PROP_IDCT_METHOD:
+ g_value_set_enum (value, dec->idct_method);
+ break;
+ case PROP_MAX_ERRORS:
+ g_value_set_int (value, g_atomic_int_get (&dec->max_errors));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstStateChangeReturn
+gst_jpeg_dec_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstJpegDec *dec;
+
+ dec = GST_JPEG_DEC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ dec->error_count = 0;
+ dec->good_count = 0;
+ dec->framerate_numerator = 0;
+ dec->framerate_denominator = 1;
+ dec->caps_framerate_numerator = dec->caps_framerate_denominator = 0;
+ dec->caps_width = -1;
+ dec->caps_height = -1;
+ dec->clrspc = -1;
+ dec->packetized = FALSE;
+ dec->next_ts = 0;
+ dec->discont = TRUE;
+ dec->parse_offset = 0;
+ dec->parse_entropy_len = 0;
+ dec->parse_resync = FALSE;
+ dec->cur_buf = NULL;
+ gst_segment_init (&dec->segment, GST_FORMAT_UNDEFINED);
+ gst_jpeg_dec_reset_qos (dec);
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret != GST_STATE_CHANGE_SUCCESS)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_adapter_clear (dec->adapter);
+ g_free (dec->cur_buf);
+ dec->cur_buf = NULL;
+ gst_jpeg_dec_free_buffers (dec);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/jpeg/gstjpegdec.h b/ext/jpeg/gstjpegdec.h
new file mode 100644
index 0000000..7daf7b6
--- /dev/null
+++ b/ext/jpeg/gstjpegdec.h
@@ -0,0 +1,150 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_JPEG_DEC_H__
+#define __GST_JPEG_DEC_H__
+
+
+#include <setjmp.h>
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/base/gstadapter.h>
+
+/* this is a hack hack hack to get around jpeglib header bugs... */
+#ifdef HAVE_STDLIB_H
+# undef HAVE_STDLIB_H
+#endif
+#include <stdio.h>
+#include <jpeglib.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_JPEG_DEC \
+ (gst_jpeg_dec_get_type())
+#define GST_JPEG_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JPEG_DEC,GstJpegDec))
+#define GST_JPEG_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JPEG_DEC,GstJpegDecClass))
+#define GST_IS_JPEG_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JPEG_DEC))
+#define GST_IS_JPEG_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JPEG_DEC))
+
+typedef struct _GstJpegDec GstJpegDec;
+typedef struct _GstJpegDecClass GstJpegDecClass;
+
+struct GstJpegDecErrorMgr {
+ struct jpeg_error_mgr pub; /* public fields */
+ jmp_buf setjmp_buffer;
+};
+
+struct GstJpegDecSourceMgr {
+ struct jpeg_source_mgr pub; /* public fields */
+ GstJpegDec *dec;
+};
+
+/* Can't use GstBaseTransform, because GstBaseTransform
+ * doesn't handle the N buffers in, 1 buffer out case,
+ * but only the 1-in 1-out case */
+struct _GstJpegDec {
+ GstElement element;
+
+ /* pads */
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ GstAdapter *adapter;
+
+ guint8 *cur_buf;
+
+ /* TRUE if each input buffer contains a whole jpeg image */
+ gboolean packetized;
+
+ /* the (expected) timestamp of the next frame */
+ guint64 next_ts;
+
+ GstSegment segment;
+
+ /* TRUE if the next output buffer should have the DISCONT flag set */
+ gboolean discont;
+
+ /* QoS stuff *//* with LOCK */
+ gdouble proportion;
+ GstClockTime earliest_time;
+ GstClockTime qos_duration;
+
+ /* video state */
+ gint framerate_numerator;
+ gint framerate_denominator;
+
+ /* negotiated state */
+ gint caps_framerate_numerator;
+ gint caps_framerate_denominator;
+ gint caps_width;
+ gint caps_height;
+ gint outsize;
+ gint clrspc;
+
+ gint offset[3];
+ gint stride;
+ gint inc;
+
+ /* parse state */
+ gint parse_offset;
+ gint parse_entropy_len;
+ gint parse_resync;
+
+ /* properties */
+ gint idct_method;
+ gint max_errors; /* ATOMIC */
+
+ /* current error (the message is the debug message) */
+ gchar *error_msg;
+ int error_line;
+ const gchar *error_func;
+
+ /* number of errors since start or last successfully decoded image */
+ guint error_count;
+
+ /* number of successfully decoded images since start */
+ guint good_count;
+
+ struct jpeg_decompress_struct cinfo;
+ struct GstJpegDecErrorMgr jerr;
+ struct GstJpegDecSourceMgr jsrc;
+
+ /* arrays for indirect decoding */
+ gboolean idr_width_allocated;
+ guchar *idr_y[16],*idr_u[16],*idr_v[16];
+ /* current (parsed) image size */
+ guint rem_img_len;
+};
+
+struct _GstJpegDecClass {
+ GstElementClass parent_class;
+};
+
+GType gst_jpeg_dec_get_type(void);
+
+
+G_END_DECLS
+
+
+#endif /* __GST_JPEG_DEC_H__ */
diff --git a/ext/jpeg/gstjpegenc.c b/ext/jpeg/gstjpegenc.c
new file mode 100644
index 0000000..c44cb2e
--- /dev/null
+++ b/ext/jpeg/gstjpegenc.c
@@ -0,0 +1,744 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:element-jpegenc
+ *
+ * Encodes jpeg images.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch videotestsrc num-buffers=50 ! video/x-raw-yuv, framerate='(fraction)'5/1 ! jpegenc ! avimux ! filesink location=mjpeg.avi
+ * ]| a pipeline to mux 5 JPEG frames per second into a 10 sec. long motion jpeg
+ * avi.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+
+#include "gstjpegenc.h"
+#include "gstjpeg.h"
+#include <gst/video/video.h>
+
+/* experimental */
+/* setting smoothig seems to have no effect in libjepeg
+#define ENABLE_SMOOTHING 1
+*/
+
+GST_DEBUG_CATEGORY_STATIC (jpegenc_debug);
+#define GST_CAT_DEFAULT jpegenc_debug
+
+#define JPEG_DEFAULT_QUALITY 85
+#define JPEG_DEFAULT_SMOOTHING 0
+#define JPEG_DEFAULT_IDCT_METHOD JDCT_FASTEST
+
+/* JpegEnc signals and args */
+enum
+{
+ FRAME_ENCODED,
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+ PROP_QUALITY,
+ PROP_SMOOTHING,
+ PROP_IDCT_METHOD
+};
+
+static void gst_jpegenc_reset (GstJpegEnc * enc);
+static void gst_jpegenc_base_init (gpointer g_class);
+static void gst_jpegenc_class_init (GstJpegEnc * klass);
+static void gst_jpegenc_init (GstJpegEnc * jpegenc);
+static void gst_jpegenc_finalize (GObject * object);
+
+static GstFlowReturn gst_jpegenc_chain (GstPad * pad, GstBuffer * buf);
+static gboolean gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps);
+static GstCaps *gst_jpegenc_getcaps (GstPad * pad);
+
+static void gst_jpegenc_resync (GstJpegEnc * jpegenc);
+static void gst_jpegenc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_jpegenc_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static GstStateChangeReturn gst_jpegenc_change_state (GstElement * element,
+ GstStateChange transition);
+
+
+static GstElementClass *parent_class = NULL;
+static guint gst_jpegenc_signals[LAST_SIGNAL] = { 0 };
+
+GType
+gst_jpegenc_get_type (void)
+{
+ static GType jpegenc_type = 0;
+
+ if (!jpegenc_type) {
+ static const GTypeInfo jpegenc_info = {
+ sizeof (GstJpegEnc),
+ (GBaseInitFunc) gst_jpegenc_base_init,
+ NULL,
+ (GClassInitFunc) gst_jpegenc_class_init,
+ NULL,
+ NULL,
+ sizeof (GstJpegEnc),
+ 0,
+ (GInstanceInitFunc) gst_jpegenc_init,
+ };
+
+ jpegenc_type =
+ g_type_register_static (GST_TYPE_ELEMENT, "GstJpegEnc", &jpegenc_info,
+ 0);
+ }
+ return jpegenc_type;
+}
+
+/* *INDENT-OFF* */
+static GstStaticPadTemplate gst_jpegenc_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV
+ ("{ I420, YV12, YUY2, UYVY, Y41B, Y42B, YVYU, Y444 }") "; "
+ GST_VIDEO_CAPS_RGB "; " GST_VIDEO_CAPS_BGR "; "
+ GST_VIDEO_CAPS_RGBx "; " GST_VIDEO_CAPS_xRGB "; "
+ GST_VIDEO_CAPS_BGRx "; " GST_VIDEO_CAPS_xBGR "; "
+ GST_VIDEO_CAPS_GRAY8)
+ );
+/* *INDENT-ON* */
+
+static GstStaticPadTemplate gst_jpegenc_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("image/jpeg, "
+ "width = (int) [ 16, 65535 ], "
+ "height = (int) [ 16, 65535 ], " "framerate = (fraction) [ 0/1, MAX ]")
+ );
+
+static void
+gst_jpegenc_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_jpegenc_sink_pad_template);
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_jpegenc_src_pad_template);
+ gst_element_class_set_details_simple (element_class, "JPEG image encoder",
+ "Codec/Encoder/Image",
+ "Encode images in JPEG format", "Wim Taymans <wim.taymans@tvd.be>");
+}
+
+static void
+gst_jpegenc_class_init (GstJpegEnc * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gst_jpegenc_signals[FRAME_ENCODED] =
+ g_signal_new ("frame-encoded", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstJpegEncClass, frame_encoded), NULL,
+ NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ gobject_class->set_property = gst_jpegenc_set_property;
+ gobject_class->get_property = gst_jpegenc_get_property;
+
+
+ g_object_class_install_property (gobject_class, PROP_QUALITY,
+ g_param_spec_int ("quality", "Quality", "Quality of encoding",
+ 0, 100, JPEG_DEFAULT_QUALITY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+#ifdef ENABLE_SMOOTHING
+ /* disabled, since it doesn't seem to work */
+ g_object_class_install_property (gobject_class, PROP_SMOOTHING,
+ g_param_spec_int ("smoothing", "Smoothing", "Smoothing factor",
+ 0, 100, JPEG_DEFAULT_SMOOTHING,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
+
+ g_object_class_install_property (gobject_class, PROP_IDCT_METHOD,
+ g_param_spec_enum ("idct-method", "IDCT Method",
+ "The IDCT algorithm to use", GST_TYPE_IDCT_METHOD,
+ JPEG_DEFAULT_IDCT_METHOD,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gstelement_class->change_state = gst_jpegenc_change_state;
+
+ gobject_class->finalize = gst_jpegenc_finalize;
+
+ GST_DEBUG_CATEGORY_INIT (jpegenc_debug, "jpegenc", 0,
+ "JPEG encoding element");
+}
+
+static void
+gst_jpegenc_init_destination (j_compress_ptr cinfo)
+{
+ GST_DEBUG ("gst_jpegenc_chain: init_destination");
+}
+
+static boolean
+gst_jpegenc_flush_destination (j_compress_ptr cinfo)
+{
+ GstBuffer *overflow_buffer;
+ guint32 old_buffer_size;
+ GstJpegEnc *jpegenc = (GstJpegEnc *) (cinfo->client_data);
+ GstFlowReturn ret;
+
+ GST_DEBUG_OBJECT (jpegenc,
+ "gst_jpegenc_chain: flush_destination: buffer too small");
+
+ /* Our output buffer wasn't big enough.
+ * Make a new buffer that's twice the size, */
+ old_buffer_size = GST_BUFFER_SIZE (jpegenc->output_buffer);
+ ret = gst_pad_alloc_buffer_and_set_caps (jpegenc->srcpad,
+ GST_BUFFER_OFFSET_NONE, old_buffer_size * 2,
+ GST_PAD_CAPS (jpegenc->srcpad), &overflow_buffer);
+ /* handle here if needed */
+ if (ret != GST_FLOW_OK) {
+ overflow_buffer = gst_buffer_new_and_alloc (old_buffer_size * 2);
+ gst_buffer_set_caps (overflow_buffer, GST_PAD_CAPS (jpegenc->srcpad));
+ }
+
+ memcpy (GST_BUFFER_DATA (overflow_buffer),
+ GST_BUFFER_DATA (jpegenc->output_buffer), old_buffer_size);
+
+ gst_buffer_copy_metadata (overflow_buffer, jpegenc->output_buffer,
+ GST_BUFFER_COPY_TIMESTAMPS);
+
+ /* drop it into place, */
+ gst_buffer_unref (jpegenc->output_buffer);
+ jpegenc->output_buffer = overflow_buffer;
+
+ /* and last, update libjpeg on where to work. */
+ jpegenc->jdest.next_output_byte =
+ GST_BUFFER_DATA (jpegenc->output_buffer) + old_buffer_size;
+ jpegenc->jdest.free_in_buffer =
+ GST_BUFFER_SIZE (jpegenc->output_buffer) - old_buffer_size;
+
+ return TRUE;
+}
+
+static void
+gst_jpegenc_term_destination (j_compress_ptr cinfo)
+{
+ GstJpegEnc *jpegenc = (GstJpegEnc *) (cinfo->client_data);
+ GST_DEBUG_OBJECT (jpegenc, "gst_jpegenc_chain: term_source");
+
+ /* Trim the buffer size and push it. */
+ GST_BUFFER_SIZE (jpegenc->output_buffer) =
+ GST_BUFFER_SIZE (jpegenc->output_buffer) - jpegenc->jdest.free_in_buffer;
+
+ g_signal_emit (G_OBJECT (jpegenc), gst_jpegenc_signals[FRAME_ENCODED], 0);
+
+ jpegenc->last_ret = gst_pad_push (jpegenc->srcpad, jpegenc->output_buffer);
+ jpegenc->output_buffer = NULL;
+}
+
+static void
+gst_jpegenc_init (GstJpegEnc * jpegenc)
+{
+ /* create the sink and src pads */
+ jpegenc->sinkpad =
+ gst_pad_new_from_static_template (&gst_jpegenc_sink_pad_template, "sink");
+ gst_pad_set_chain_function (jpegenc->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_jpegenc_chain));
+ gst_pad_set_getcaps_function (jpegenc->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_jpegenc_getcaps));
+ gst_pad_set_setcaps_function (jpegenc->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_jpegenc_setcaps));
+ gst_element_add_pad (GST_ELEMENT (jpegenc), jpegenc->sinkpad);
+
+ jpegenc->srcpad =
+ gst_pad_new_from_static_template (&gst_jpegenc_src_pad_template, "src");
+ gst_pad_use_fixed_caps (jpegenc->srcpad);
+ gst_element_add_pad (GST_ELEMENT (jpegenc), jpegenc->srcpad);
+
+ /* reset the initial video state */
+ jpegenc->width = -1;
+ jpegenc->height = -1;
+
+ /* setup jpeglib */
+ memset (&jpegenc->cinfo, 0, sizeof (jpegenc->cinfo));
+ memset (&jpegenc->jerr, 0, sizeof (jpegenc->jerr));
+ jpegenc->cinfo.err = jpeg_std_error (&jpegenc->jerr);
+ jpeg_create_compress (&jpegenc->cinfo);
+
+ jpegenc->jdest.init_destination = gst_jpegenc_init_destination;
+ jpegenc->jdest.empty_output_buffer = gst_jpegenc_flush_destination;
+ jpegenc->jdest.term_destination = gst_jpegenc_term_destination;
+ jpegenc->cinfo.dest = &jpegenc->jdest;
+ jpegenc->cinfo.client_data = jpegenc;
+
+ /* init properties */
+ jpegenc->quality = JPEG_DEFAULT_QUALITY;
+ jpegenc->smoothing = JPEG_DEFAULT_SMOOTHING;
+ jpegenc->idct_method = JPEG_DEFAULT_IDCT_METHOD;
+
+ gst_jpegenc_reset (jpegenc);
+}
+
+static void
+gst_jpegenc_reset (GstJpegEnc * enc)
+{
+ gint i, j;
+
+ g_free (enc->line[0]);
+ g_free (enc->line[1]);
+ g_free (enc->line[2]);
+ enc->line[0] = NULL;
+ enc->line[1] = NULL;
+ enc->line[2] = NULL;
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 4 * DCTSIZE; j++) {
+ g_free (enc->row[i][j]);
+ enc->row[i][j] = NULL;
+ }
+ }
+
+ enc->width = -1;
+ enc->height = -1;
+ enc->format = GST_VIDEO_FORMAT_UNKNOWN;
+ enc->fps_den = enc->par_den = 0;
+ enc->height = enc->width = 0;
+}
+
+static void
+gst_jpegenc_finalize (GObject * object)
+{
+ GstJpegEnc *filter = GST_JPEGENC (object);
+
+ jpeg_destroy_compress (&filter->cinfo);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_jpegenc_getcaps (GstPad * pad)
+{
+ GstJpegEnc *jpegenc = GST_JPEGENC (gst_pad_get_parent (pad));
+ GstCaps *caps, *othercaps;
+ const GstCaps *templ;
+ gint i, j;
+ GstStructure *structure = NULL;
+
+ /* we want to proxy properties like width, height and framerate from the
+ other end of the element */
+
+ othercaps = gst_pad_peer_get_caps_reffed (jpegenc->srcpad);
+ if (othercaps == NULL ||
+ gst_caps_is_empty (othercaps) || gst_caps_is_any (othercaps)) {
+ caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+ goto done;
+ }
+
+ caps = gst_caps_new_empty ();
+ templ = gst_pad_get_pad_template_caps (pad);
+
+ for (i = 0; i < gst_caps_get_size (templ); i++) {
+ /* pick fields from peer caps */
+ for (j = 0; j < gst_caps_get_size (othercaps); j++) {
+ GstStructure *s = gst_caps_get_structure (othercaps, j);
+ const GValue *val;
+
+ structure = gst_structure_copy (gst_caps_get_structure (templ, i));
+ if ((val = gst_structure_get_value (s, "width")))
+ gst_structure_set_value (structure, "width", val);
+ if ((val = gst_structure_get_value (s, "height")))
+ gst_structure_set_value (structure, "height", val);
+ if ((val = gst_structure_get_value (s, "framerate")))
+ gst_structure_set_value (structure, "framerate", val);
+
+ gst_caps_merge_structure (caps, structure);
+ }
+ }
+
+done:
+
+ gst_caps_replace (&othercaps, NULL);
+ gst_object_unref (jpegenc);
+
+ return caps;
+}
+
+static gboolean
+gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstJpegEnc *enc = GST_JPEGENC (gst_pad_get_parent (pad));
+ GstVideoFormat format;
+ gint width, height;
+ gint fps_num, fps_den;
+ gint par_num, par_den;
+ gint i;
+ GstCaps *othercaps;
+ gboolean ret;
+
+ /* get info from caps */
+ if (!gst_video_format_parse_caps (caps, &format, &width, &height))
+ goto refuse_caps;
+ /* optional; pass along if present */
+ fps_num = fps_den = -1;
+ par_num = par_den = -1;
+ gst_video_parse_caps_framerate (caps, &fps_num, &fps_den);
+ gst_video_parse_caps_pixel_aspect_ratio (caps, &par_num, &par_den);
+
+ if (width == enc->width && height == enc->height && enc->format == format
+ && fps_num == enc->fps_num && fps_den == enc->fps_den
+ && par_num == enc->par_num && par_den == enc->par_den)
+ return TRUE;
+
+ /* store input description */
+ enc->format = format;
+ enc->width = width;
+ enc->height = height;
+ enc->fps_num = fps_num;
+ enc->fps_den = fps_den;
+ enc->par_num = par_num;
+ enc->par_den = par_den;
+
+ /* prepare a cached image description */
+ enc->channels = 3 + (gst_video_format_has_alpha (format) ? 1 : 0);
+ /* ... but any alpha is disregarded in encoding */
+ if (gst_video_format_is_gray (format))
+ enc->channels = 1;
+ else
+ enc->channels = 3;
+ enc->h_max_samp = 0;
+ enc->v_max_samp = 0;
+ for (i = 0; i < enc->channels; ++i) {
+ enc->cwidth[i] = gst_video_format_get_component_width (format, i, width);
+ enc->cheight[i] = gst_video_format_get_component_height (format, i, height);
+ enc->offset[i] = gst_video_format_get_component_offset (format, i, width,
+ height);
+ enc->stride[i] = gst_video_format_get_row_stride (format, i, width);
+ enc->inc[i] = gst_video_format_get_pixel_stride (format, i);
+ enc->h_samp[i] = GST_ROUND_UP_4 (width) / enc->cwidth[i];
+ enc->h_max_samp = MAX (enc->h_max_samp, enc->h_samp[i]);
+ enc->v_samp[i] = GST_ROUND_UP_4 (height) / enc->cheight[i];
+ enc->v_max_samp = MAX (enc->v_max_samp, enc->v_samp[i]);
+ }
+ /* samp should only be 1, 2 or 4 */
+ g_assert (enc->h_max_samp <= 4);
+ g_assert (enc->v_max_samp <= 4);
+ /* now invert */
+ /* maximum is invariant, as one of the components should have samp 1 */
+ for (i = 0; i < enc->channels; ++i) {
+ enc->h_samp[i] = enc->h_max_samp / enc->h_samp[i];
+ enc->v_samp[i] = enc->v_max_samp / enc->v_samp[i];
+ }
+ enc->planar = (enc->inc[0] == 1 && enc->inc[1] == 1 && enc->inc[2] == 1);
+
+ othercaps = gst_caps_copy (gst_pad_get_pad_template_caps (enc->srcpad));
+ gst_caps_set_simple (othercaps,
+ "width", G_TYPE_INT, enc->width, "height", G_TYPE_INT, enc->height, NULL);
+ if (enc->fps_den > 0)
+ gst_caps_set_simple (othercaps,
+ "framerate", GST_TYPE_FRACTION, enc->fps_num, enc->fps_den, NULL);
+ if (enc->par_den > 0)
+ gst_caps_set_simple (othercaps,
+ "pixel-aspect-ratio", GST_TYPE_FRACTION, enc->par_num, enc->par_den,
+ NULL);
+
+ ret = gst_pad_set_caps (enc->srcpad, othercaps);
+ gst_caps_unref (othercaps);
+
+ if (ret)
+ gst_jpegenc_resync (enc);
+
+ gst_object_unref (enc);
+
+ return ret;
+
+ /* ERRORS */
+refuse_caps:
+ {
+ GST_WARNING_OBJECT (enc, "refused caps %" GST_PTR_FORMAT, caps);
+ gst_object_unref (enc);
+ return FALSE;
+ }
+}
+
+static void
+gst_jpegenc_resync (GstJpegEnc * jpegenc)
+{
+ gint width, height;
+ gint i, j;
+
+ GST_DEBUG_OBJECT (jpegenc, "resync");
+
+ jpegenc->cinfo.image_width = width = jpegenc->width;
+ jpegenc->cinfo.image_height = height = jpegenc->height;
+ jpegenc->cinfo.input_components = jpegenc->channels;
+
+ GST_DEBUG_OBJECT (jpegenc, "width %d, height %d", width, height);
+ GST_DEBUG_OBJECT (jpegenc, "format %d", jpegenc->format);
+
+ if (gst_video_format_is_rgb (jpegenc->format)) {
+ GST_DEBUG_OBJECT (jpegenc, "RGB");
+ jpegenc->cinfo.in_color_space = JCS_RGB;
+ } else if (gst_video_format_is_gray (jpegenc->format)) {
+ GST_DEBUG_OBJECT (jpegenc, "gray");
+ jpegenc->cinfo.in_color_space = JCS_GRAYSCALE;
+ } else {
+ GST_DEBUG_OBJECT (jpegenc, "YUV");
+ jpegenc->cinfo.in_color_space = JCS_YCbCr;
+ }
+
+ /* input buffer size as max output */
+ jpegenc->bufsize = gst_video_format_get_size (jpegenc->format, width, height);
+ jpeg_set_defaults (&jpegenc->cinfo);
+ jpegenc->cinfo.raw_data_in = TRUE;
+ /* duh, libjpeg maps RGB to YUV ... and don't expect some conversion */
+ if (jpegenc->cinfo.in_color_space == JCS_RGB)
+ jpeg_set_colorspace (&jpegenc->cinfo, JCS_RGB);
+
+ GST_DEBUG_OBJECT (jpegenc, "h_max_samp=%d, v_max_samp=%d",
+ jpegenc->h_max_samp, jpegenc->v_max_samp);
+ /* image dimension info */
+ for (i = 0; i < jpegenc->channels; i++) {
+ GST_DEBUG_OBJECT (jpegenc, "comp %i: h_samp=%d, v_samp=%d", i,
+ jpegenc->h_samp[i], jpegenc->v_samp[i]);
+ jpegenc->cinfo.comp_info[i].h_samp_factor = jpegenc->h_samp[i];
+ jpegenc->cinfo.comp_info[i].v_samp_factor = jpegenc->v_samp[i];
+ g_free (jpegenc->line[i]);
+ jpegenc->line[i] = g_new (guchar *, jpegenc->v_max_samp * DCTSIZE);
+ if (!jpegenc->planar) {
+ for (j = 0; j < jpegenc->v_max_samp * DCTSIZE; j++) {
+ g_free (jpegenc->row[i][j]);
+ jpegenc->row[i][j] = g_malloc (width);
+ jpegenc->line[i][j] = jpegenc->row[i][j];
+ }
+ }
+ }
+
+ /* guard against a potential error in gst_jpegenc_term_destination
+ which occurs iff bufsize % 4 < free_space_remaining */
+ jpegenc->bufsize = GST_ROUND_UP_4 (jpegenc->bufsize);
+
+ jpeg_suppress_tables (&jpegenc->cinfo, TRUE);
+
+ GST_DEBUG_OBJECT (jpegenc, "resync done");
+}
+
+static GstFlowReturn
+gst_jpegenc_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstFlowReturn ret;
+ GstJpegEnc *jpegenc;
+ guchar *data;
+ gulong size;
+ guint height;
+ guchar *base[3], *end[3];
+ gint i, j, k;
+
+ jpegenc = GST_JPEGENC (GST_OBJECT_PARENT (pad));
+
+ if (G_UNLIKELY (jpegenc->width <= 0 || jpegenc->height <= 0))
+ goto not_negotiated;
+
+ data = GST_BUFFER_DATA (buf);
+ size = GST_BUFFER_SIZE (buf);
+
+ GST_LOG_OBJECT (jpegenc, "got buffer of %lu bytes", size);
+
+ ret =
+ gst_pad_alloc_buffer_and_set_caps (jpegenc->srcpad,
+ GST_BUFFER_OFFSET_NONE, jpegenc->bufsize, GST_PAD_CAPS (jpegenc->srcpad),
+ &jpegenc->output_buffer);
+
+ if (ret != GST_FLOW_OK)
+ goto done;
+
+ gst_buffer_copy_metadata (jpegenc->output_buffer, buf,
+ GST_BUFFER_COPY_TIMESTAMPS);
+
+ height = jpegenc->height;
+
+ for (i = 0; i < jpegenc->channels; i++) {
+ base[i] = data + jpegenc->offset[i];
+ end[i] = base[i] + jpegenc->cheight[i] * jpegenc->stride[i];
+ }
+
+ jpegenc->jdest.next_output_byte = GST_BUFFER_DATA (jpegenc->output_buffer);
+ jpegenc->jdest.free_in_buffer = GST_BUFFER_SIZE (jpegenc->output_buffer);
+
+ /* prepare for raw input */
+#if JPEG_LIB_VERSION >= 70
+ jpegenc->cinfo.do_fancy_downsampling = FALSE;
+#endif
+ jpegenc->cinfo.smoothing_factor = jpegenc->smoothing;
+ jpegenc->cinfo.dct_method = jpegenc->idct_method;
+ jpeg_set_quality (&jpegenc->cinfo, jpegenc->quality, TRUE);
+ jpeg_start_compress (&jpegenc->cinfo, TRUE);
+
+ GST_LOG_OBJECT (jpegenc, "compressing");
+
+ if (jpegenc->planar) {
+ for (i = 0; i < height; i += jpegenc->v_max_samp * DCTSIZE) {
+ for (k = 0; k < jpegenc->channels; k++) {
+ for (j = 0; j < jpegenc->v_samp[k] * DCTSIZE; j++) {
+ jpegenc->line[k][j] = base[k];
+ if (base[k] + jpegenc->stride[k] < end[k])
+ base[k] += jpegenc->stride[k];
+ }
+ }
+ jpeg_write_raw_data (&jpegenc->cinfo, jpegenc->line,
+ jpegenc->v_max_samp * DCTSIZE);
+ }
+ } else {
+ for (i = 0; i < height; i += jpegenc->v_max_samp * DCTSIZE) {
+ for (k = 0; k < jpegenc->channels; k++) {
+ for (j = 0; j < jpegenc->v_samp[k] * DCTSIZE; j++) {
+ guchar *src, *dst;
+ gint l;
+
+ /* ouch, copy line */
+ src = base[k];
+ dst = jpegenc->line[k][j];
+ for (l = jpegenc->cwidth[k]; l > 0; l--) {
+ *dst = *src;
+ src += jpegenc->inc[k];
+ dst++;
+ }
+ if (base[k] + jpegenc->stride[k] < end[k])
+ base[k] += jpegenc->stride[k];
+ }
+ }
+ jpeg_write_raw_data (&jpegenc->cinfo, jpegenc->line,
+ jpegenc->v_max_samp * DCTSIZE);
+ }
+ }
+
+ /* This will ensure that gst_jpegenc_term_destination is called; we push
+ the final output buffer from there */
+ jpeg_finish_compress (&jpegenc->cinfo);
+ GST_LOG_OBJECT (jpegenc, "compressing done");
+
+done:
+ gst_buffer_unref (buf);
+
+ return ret;
+
+/* ERRORS */
+not_negotiated:
+ {
+ GST_WARNING_OBJECT (jpegenc, "no input format set (no caps on buffer)");
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ goto done;
+ }
+}
+
+static void
+gst_jpegenc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstJpegEnc *jpegenc = GST_JPEGENC (object);
+
+ GST_OBJECT_LOCK (jpegenc);
+
+ switch (prop_id) {
+ case PROP_QUALITY:
+ jpegenc->quality = g_value_get_int (value);
+ break;
+#ifdef ENABLE_SMOOTHING
+ case PROP_SMOOTHING:
+ jpegenc->smoothing = g_value_get_int (value);
+ break;
+#endif
+ case PROP_IDCT_METHOD:
+ jpegenc->idct_method = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ GST_OBJECT_UNLOCK (jpegenc);
+}
+
+static void
+gst_jpegenc_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstJpegEnc *jpegenc = GST_JPEGENC (object);
+
+ GST_OBJECT_LOCK (jpegenc);
+
+ switch (prop_id) {
+ case PROP_QUALITY:
+ g_value_set_int (value, jpegenc->quality);
+ break;
+#ifdef ENABLE_SMOOTHING
+ case PROP_SMOOTHING:
+ g_value_set_int (value, jpegenc->smoothing);
+ break;
+#endif
+ case PROP_IDCT_METHOD:
+ g_value_set_enum (value, jpegenc->idct_method);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ GST_OBJECT_UNLOCK (jpegenc);
+}
+
+static GstStateChangeReturn
+gst_jpegenc_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstJpegEnc *filter = GST_JPEGENC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ GST_DEBUG_OBJECT (element, "setting line buffers");
+ filter->line[0] = NULL;
+ filter->line[1] = NULL;
+ filter->line[2] = NULL;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_jpegenc_reset (filter);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/jpeg/gstjpegenc.h b/ext/jpeg/gstjpegenc.h
new file mode 100644
index 0000000..f7a3ef0
--- /dev/null
+++ b/ext/jpeg/gstjpegenc.h
@@ -0,0 +1,109 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_JPEGENC_H__
+#define __GST_JPEGENC_H__
+
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+/* this is a hack hack hack to get around jpeglib header bugs... */
+#ifdef HAVE_STDLIB_H
+# undef HAVE_STDLIB_H
+#endif
+#include <stdio.h>
+#include <jpeglib.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_JPEGENC \
+ (gst_jpegenc_get_type())
+#define GST_JPEGENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JPEGENC,GstJpegEnc))
+#define GST_JPEGENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JPEGENC,GstJpegEncClass))
+#define GST_IS_JPEGENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JPEGENC))
+#define GST_IS_JPEGENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JPEGENC))
+
+typedef struct _GstJpegEnc GstJpegEnc;
+typedef struct _GstJpegEncClass GstJpegEncClass;
+
+#define GST_JPEG_ENC_MAX_COMPONENT 4
+
+struct _GstJpegEnc
+{
+ GstElement element;
+
+ /* pads */
+ GstPad *sinkpad, *srcpad;
+
+ /* stream/image properties */
+ GstVideoFormat format;
+ gint width;
+ gint height;
+ gint channels;
+ gint fps_num, fps_den;
+ gint par_num, par_den;
+ /* standard video_format indexed */
+ gint stride[GST_JPEG_ENC_MAX_COMPONENT];
+ gint offset[GST_JPEG_ENC_MAX_COMPONENT];
+ gint inc[GST_JPEG_ENC_MAX_COMPONENT];
+ gint cwidth[GST_JPEG_ENC_MAX_COMPONENT];
+ gint cheight[GST_JPEG_ENC_MAX_COMPONENT];
+ gint h_samp[GST_JPEG_ENC_MAX_COMPONENT];
+ gint v_samp[GST_JPEG_ENC_MAX_COMPONENT];
+ gint h_max_samp;
+ gint v_max_samp;
+ gboolean planar;
+ /* the video buffer */
+ gint bufsize;
+ /* the jpeg line buffer */
+ guchar **line[3];
+ /* indirect encoding line buffers */
+ guchar *row[3][4 * DCTSIZE];
+
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ struct jpeg_destination_mgr jdest;
+
+ /* properties */
+ gint quality;
+ gint smoothing;
+ gint idct_method;
+
+ /* cached return state for any problems that may occur in callbacks */
+ GstFlowReturn last_ret;
+
+ GstBuffer *output_buffer;
+};
+
+struct _GstJpegEncClass
+{
+ GstElementClass parent_class;
+
+ /* signals */
+ void (*frame_encoded) (GstElement * element);
+};
+
+GType gst_jpegenc_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_JPEGENC_H__ */
diff --git a/ext/jpeg/gstsmokedec.c b/ext/jpeg/gstsmokedec.c
new file mode 100644
index 0000000..6e38bb9
--- /dev/null
+++ b/ext/jpeg/gstsmokedec.c
@@ -0,0 +1,332 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-smokedec
+ *
+ * Decodes images in smoke format.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+
+/*#define DEBUG_ENABLED*/
+#include "gstsmokedec.h"
+#include <gst/video/video.h>
+
+GST_DEBUG_CATEGORY_STATIC (smokedec_debug);
+#define GST_CAT_DEFAULT smokedec_debug
+
+/* SmokeDec signals and args */
+enum
+{
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0
+};
+
+static void gst_smokedec_base_init (gpointer g_class);
+static void gst_smokedec_class_init (GstSmokeDec * klass);
+static void gst_smokedec_init (GstSmokeDec * smokedec);
+static void gst_smokedec_finalize (GObject * object);
+
+static GstStateChangeReturn
+gst_smokedec_change_state (GstElement * element, GstStateChange transition);
+
+static GstFlowReturn gst_smokedec_chain (GstPad * pad, GstBuffer * buf);
+
+static GstElementClass *parent_class = NULL;
+
+/*static guint gst_smokedec_signals[LAST_SIGNAL] = { 0 }; */
+
+GType
+gst_smokedec_get_type (void)
+{
+ static GType smokedec_type = 0;
+
+ if (!smokedec_type) {
+ static const GTypeInfo smokedec_info = {
+ sizeof (GstSmokeDecClass),
+ gst_smokedec_base_init,
+ NULL,
+ (GClassInitFunc) gst_smokedec_class_init,
+ NULL,
+ NULL,
+ sizeof (GstSmokeDec),
+ 0,
+ (GInstanceInitFunc) gst_smokedec_init,
+ };
+
+ smokedec_type =
+ g_type_register_static (GST_TYPE_ELEMENT, "GstSmokeDec", &smokedec_info,
+ 0);
+ }
+ return smokedec_type;
+}
+
+static GstStaticPadTemplate gst_smokedec_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
+ );
+
+static GstStaticPadTemplate gst_smokedec_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-smoke, "
+ "width = (int) [ 16, 4096 ], "
+ "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0/1, MAX ]")
+ );
+
+static void
+gst_smokedec_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_smokedec_src_pad_template);
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_smokedec_sink_pad_template);
+ gst_element_class_set_details_simple (element_class, "Smoke video decoder",
+ "Codec/Decoder/Video",
+ "Decode video from Smoke format", "Wim Taymans <wim@fluendo.com>");
+}
+
+static void
+gst_smokedec_class_init (GstSmokeDec * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->finalize = gst_smokedec_finalize;
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_smokedec_change_state);
+
+ GST_DEBUG_CATEGORY_INIT (smokedec_debug, "smokedec", 0, "Smoke decoder");
+}
+
+static void
+gst_smokedec_init (GstSmokeDec * smokedec)
+{
+ GST_DEBUG_OBJECT (smokedec, "gst_smokedec_init: initializing");
+ /* create the sink and src pads */
+
+ smokedec->sinkpad =
+ gst_pad_new_from_static_template (&gst_smokedec_sink_pad_template,
+ "sink");
+ gst_pad_set_chain_function (smokedec->sinkpad, gst_smokedec_chain);
+ gst_element_add_pad (GST_ELEMENT (smokedec), smokedec->sinkpad);
+
+ smokedec->srcpad =
+ gst_pad_new_from_static_template (&gst_smokedec_src_pad_template, "src");
+ gst_pad_use_fixed_caps (smokedec->srcpad);
+ gst_element_add_pad (GST_ELEMENT (smokedec), smokedec->srcpad);
+
+ smokecodec_decode_new (&smokedec->info);
+}
+
+static void
+gst_smokedec_finalize (GObject * object)
+{
+ GstSmokeDec *dec = GST_SMOKEDEC (object);
+
+ smokecodec_info_free (dec->info);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstFlowReturn
+gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstSmokeDec *smokedec;
+ guint8 *data, *outdata;
+ gulong size, outsize;
+ GstBuffer *outbuf;
+ SmokeCodecFlags flags;
+ GstClockTime time;
+ guint width, height;
+ guint fps_num, fps_denom;
+ gint smokeret;
+ GstFlowReturn ret;
+
+ smokedec = GST_SMOKEDEC (gst_pad_get_parent (pad));
+
+ data = GST_BUFFER_DATA (buf);
+ size = GST_BUFFER_SIZE (buf);
+ time = GST_BUFFER_TIMESTAMP (buf);
+
+ if (size < 1)
+ goto too_small;
+
+ GST_LOG_OBJECT (smokedec, "got buffer of %lu bytes", size);
+
+ /* have the ID packet. */
+ if (data[0] == SMOKECODEC_TYPE_ID) {
+ smokeret = smokecodec_parse_id (smokedec->info, data, size);
+ if (smokeret != SMOKECODEC_OK)
+ goto header_error;
+
+ ret = GST_FLOW_OK;
+ goto done;
+ }
+
+ /* now handle data packets */
+ GST_DEBUG_OBJECT (smokedec, "reading header %08lx", *(gulong *) data);
+ smokecodec_parse_header (smokedec->info, data, size, &flags, &width, &height,
+ &fps_num, &fps_denom);
+
+ if (smokedec->height != height || smokedec->width != width ||
+ smokedec->fps_num != fps_num || smokedec->fps_denom != fps_denom) {
+ GstCaps *caps;
+
+ GST_DEBUG_OBJECT (smokedec, "parameter change: %dx%d @ %d/%dfps",
+ width, height, fps_num, fps_denom);
+
+ smokedec->height = height;
+ smokedec->width = width;
+
+ caps = gst_caps_new_simple ("video/x-raw-yuv",
+ "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
+ "width", G_TYPE_INT, width,
+ "height", G_TYPE_INT, height,
+ "framerate", GST_TYPE_FRACTION, fps_num, fps_denom, NULL);
+
+ gst_pad_set_caps (smokedec->srcpad, caps);
+ gst_caps_unref (caps);
+ }
+
+ if (smokedec->need_keyframe) {
+ if (!(flags & SMOKECODEC_KEYFRAME))
+ goto keyframe_skip;
+
+ smokedec->need_keyframe = FALSE;
+ }
+
+ outsize = width * height + width * height / 2;
+ outbuf = gst_buffer_new_and_alloc (outsize);
+ outdata = GST_BUFFER_DATA (outbuf);
+
+ GST_BUFFER_DURATION (outbuf) =
+ gst_util_uint64_scale_int (GST_SECOND, fps_denom, fps_num);
+ GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf);
+ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smokedec->srcpad));
+
+ if (time == GST_CLOCK_TIME_NONE) {
+ if (GST_BUFFER_OFFSET (buf) == -1) {
+ time = smokedec->next_time;
+ } else {
+ time = GST_BUFFER_OFFSET (buf) * GST_BUFFER_DURATION (outbuf);
+ }
+ }
+ GST_BUFFER_TIMESTAMP (outbuf) = time;
+ if (time != -1)
+ smokedec->next_time = time + GST_BUFFER_DURATION (outbuf);
+ else
+ smokedec->next_time = -1;
+
+ smokeret = smokecodec_decode (smokedec->info, data, size, outdata);
+ if (smokeret != SMOKECODEC_OK)
+ goto decode_error;
+
+ GST_DEBUG_OBJECT (smokedec, "gst_smokedec_chain: sending buffer");
+ ret = gst_pad_push (smokedec->srcpad, outbuf);
+
+done:
+ gst_buffer_unref (buf);
+ gst_object_unref (smokedec);
+
+ return ret;
+
+ /* ERRORS */
+too_small:
+ {
+ GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
+ (NULL), ("Input buffer too small"));
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+header_error:
+ {
+ GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
+ (NULL), ("Could not parse smoke header, reason: %d", smokeret));
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+keyframe_skip:
+ {
+ GST_DEBUG_OBJECT (smokedec, "dropping buffer while waiting for keyframe");
+ ret = GST_FLOW_OK;
+ goto done;
+ }
+decode_error:
+ {
+ GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
+ (NULL), ("Could not decode smoke frame, reason: %d", smokeret));
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+}
+
+static GstStateChangeReturn
+gst_smokedec_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstSmokeDec *dec;
+
+ dec = GST_SMOKEDEC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ /* reset the initial video state */
+ dec->format = -1;
+ dec->width = -1;
+ dec->height = -1;
+ dec->fps_num = -1;
+ dec->fps_denom = -1;
+ dec->next_time = 0;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret != GST_STATE_CHANGE_SUCCESS)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/jpeg/gstsmokedec.h b/ext/jpeg/gstsmokedec.h
new file mode 100644
index 0000000..ffece2b
--- /dev/null
+++ b/ext/jpeg/gstsmokedec.h
@@ -0,0 +1,75 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_SMOKEDEC_H__
+#define __GST_SMOKEDEC_H__
+
+
+#include <gst/gst.h>
+#include "smokecodec.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SMOKEDEC \
+ (gst_smokedec_get_type())
+#define GST_SMOKEDEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SMOKEDEC,GstSmokeDec))
+#define GST_SMOKEDEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SMOKEDEC,GstSmokeDecClass))
+#define GST_IS_SMOKEDEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SMOKEDEC))
+#define GST_IS_SMOKEDEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SMOKEDEC))
+
+typedef struct _GstSmokeDec GstSmokeDec;
+typedef struct _GstSmokeDecClass GstSmokeDecClass;
+
+struct _GstSmokeDec {
+ GstElement element;
+
+ /* pads */
+ GstPad *sinkpad,*srcpad;
+
+ /* video state */
+ gint format;
+ gint width;
+ gint height;
+ gint fps_num;
+ gint fps_denom;
+ GstClockTime next_time;
+
+ SmokeCodecInfo *info;
+
+ gint threshold;
+ gint quality;
+ gint smoothing;
+
+ gboolean need_keyframe;
+};
+
+struct _GstSmokeDecClass {
+ GstElementClass parent_class;
+};
+
+GType gst_smokedec_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_SMOKEDEC_H__ */
diff --git a/ext/jpeg/gstsmokeenc.c b/ext/jpeg/gstsmokeenc.c
new file mode 100644
index 0000000..5bd4d99
--- /dev/null
+++ b/ext/jpeg/gstsmokeenc.c
@@ -0,0 +1,509 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:element-smokeenc
+ *
+ * Encodes images in smoke format.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+
+#include "gstsmokeenc.h"
+#include <gst/video/video.h>
+
+GST_DEBUG_CATEGORY_STATIC (smokeenc_debug);
+#define GST_CAT_DEFAULT smokeenc_debug
+
+
+/* SmokeEnc signals and args */
+enum
+{
+ FRAME_ENCODED,
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+#define DEFAULT_PROP_MIN_QUALITY 10
+#define DEFAULT_PROP_MAX_QUALITY 85
+#define DEFAULT_PROP_THRESHOLD 3000
+#define DEFAULT_PROP_KEYFRAME 20
+
+enum
+{
+ PROP_0,
+ PROP_MIN_QUALITY,
+ PROP_MAX_QUALITY,
+ PROP_THRESHOLD,
+ PROP_KEYFRAME
+ /* FILL ME */
+};
+
+static void gst_smokeenc_base_init (gpointer g_class);
+static void gst_smokeenc_class_init (GstSmokeEnc * klass);
+static void gst_smokeenc_init (GstSmokeEnc * smokeenc);
+static void gst_smokeenc_finalize (GObject * object);
+
+static GstStateChangeReturn
+gst_smokeenc_change_state (GstElement * element, GstStateChange transition);
+
+static GstFlowReturn gst_smokeenc_chain (GstPad * pad, GstBuffer * buf);
+static GstCaps *gst_smokeenc_getcaps (GstPad * pad);
+static gboolean gst_smokeenc_setcaps (GstPad * pad, GstCaps * caps);
+
+static gboolean gst_smokeenc_resync (GstSmokeEnc * smokeenc);
+static void gst_smokeenc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_smokeenc_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstElementClass *parent_class = NULL;
+
+GType
+gst_smokeenc_get_type (void)
+{
+ static GType smokeenc_type = 0;
+
+ if (!smokeenc_type) {
+ static const GTypeInfo smokeenc_info = {
+ sizeof (GstSmokeEncClass),
+ (GBaseInitFunc) gst_smokeenc_base_init,
+ NULL,
+ (GClassInitFunc) gst_smokeenc_class_init,
+ NULL,
+ NULL,
+ sizeof (GstSmokeEnc),
+ 0,
+ (GInstanceInitFunc) gst_smokeenc_init,
+ };
+
+ smokeenc_type =
+ g_type_register_static (GST_TYPE_ELEMENT, "GstSmokeEnc", &smokeenc_info,
+ 0);
+ }
+ return smokeenc_type;
+}
+
+static GstStaticPadTemplate gst_smokeenc_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
+ );
+
+static GstStaticPadTemplate gst_smokeenc_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-smoke, "
+ "width = (int) [ 16, 4096 ], "
+ "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0/1, MAX ]")
+ );
+
+static void
+gst_smokeenc_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_smokeenc_sink_pad_template);
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_smokeenc_src_pad_template);
+ gst_element_class_set_details_simple (element_class, "Smoke video encoder",
+ "Codec/Encoder/Video",
+ "Encode images into the Smoke format", "Wim Taymans <wim@fluendo.com>");
+}
+
+static void
+gst_smokeenc_class_init (GstSmokeEnc * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->finalize = gst_smokeenc_finalize;
+ gobject_class->set_property = gst_smokeenc_set_property;
+ gobject_class->get_property = gst_smokeenc_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_MIN_QUALITY,
+ g_param_spec_int ("qmin", "Qmin", "Minimum quality",
+ 0, 100, DEFAULT_PROP_MIN_QUALITY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_MAX_QUALITY,
+ g_param_spec_int ("qmax", "Qmax", "Maximum quality",
+ 0, 100, DEFAULT_PROP_MAX_QUALITY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_THRESHOLD,
+ g_param_spec_int ("threshold", "Threshold", "Motion estimation threshold",
+ 0, 100000000, DEFAULT_PROP_THRESHOLD,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_KEYFRAME,
+ g_param_spec_int ("keyframe", "Keyframe",
+ "Insert keyframe every N frames", 1, 100000,
+ DEFAULT_PROP_KEYFRAME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_smokeenc_change_state);
+
+ GST_DEBUG_CATEGORY_INIT (smokeenc_debug, "smokeenc", 0,
+ "Smoke encoding element");
+}
+
+static void
+gst_smokeenc_init (GstSmokeEnc * smokeenc)
+{
+ /* create the sink and src pads */
+ smokeenc->sinkpad =
+ gst_pad_new_from_static_template (&gst_smokeenc_sink_pad_template,
+ "sink");
+ gst_pad_set_chain_function (smokeenc->sinkpad, gst_smokeenc_chain);
+ gst_pad_set_getcaps_function (smokeenc->sinkpad, gst_smokeenc_getcaps);
+ gst_pad_set_setcaps_function (smokeenc->sinkpad, gst_smokeenc_setcaps);
+ gst_element_add_pad (GST_ELEMENT (smokeenc), smokeenc->sinkpad);
+
+ smokeenc->srcpad =
+ gst_pad_new_from_static_template (&gst_smokeenc_src_pad_template, "src");
+ gst_pad_set_getcaps_function (smokeenc->srcpad, gst_smokeenc_getcaps);
+ gst_pad_use_fixed_caps (smokeenc->srcpad);
+ gst_element_add_pad (GST_ELEMENT (smokeenc), smokeenc->srcpad);
+
+ smokeenc->min_quality = DEFAULT_PROP_MIN_QUALITY;
+ smokeenc->max_quality = DEFAULT_PROP_MAX_QUALITY;
+ smokeenc->threshold = DEFAULT_PROP_THRESHOLD;
+ smokeenc->keyframe = DEFAULT_PROP_KEYFRAME;
+}
+
+static void
+gst_smokeenc_finalize (GObject * object)
+{
+ GstSmokeEnc *enc = GST_SMOKEENC (object);
+
+ if (enc->info)
+ smokecodec_info_free (enc->info);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_smokeenc_getcaps (GstPad * pad)
+{
+ GstSmokeEnc *smokeenc = GST_SMOKEENC (gst_pad_get_parent (pad));
+ GstPad *otherpad;
+ GstCaps *result, *caps;
+ const GstCaps *tcaps;
+ const char *name;
+ int i;
+ GstStructure *structure = NULL;
+
+ /* we want to proxy properties like width, height and framerate from the
+ other end of the element */
+ otherpad = (pad == smokeenc->srcpad) ? smokeenc->sinkpad : smokeenc->srcpad;
+
+ /* get template caps, we always need this to fiter the peer caps */
+ tcaps = gst_pad_get_pad_template_caps (otherpad);
+
+ /* get any constraints on the peer pad */
+ caps = gst_pad_peer_get_caps (otherpad);
+
+ if (caps == NULL)
+ caps = gst_caps_copy (tcaps);
+ else
+ caps = gst_caps_make_writable (caps);
+
+ /* intersect with the template */
+ result = gst_caps_intersect (caps, tcaps);
+ gst_caps_unref (caps);
+
+ if (pad == smokeenc->srcpad) {
+ name = "video/x-smoke";
+ } else {
+ name = "video/x-raw-yuv";
+ }
+
+ /* we can only copy width, height, framerate from one side to the other */
+ for (i = 0; i < gst_caps_get_size (result); i++) {
+ structure = gst_caps_get_structure (result, i);
+
+ gst_structure_set_name (structure, name);
+ gst_structure_remove_field (structure, "format");
+ /* ... but for the sink pad, we only do I420 anyway, so add that */
+ if (pad == smokeenc->sinkpad) {
+ gst_structure_set (structure, "format", GST_TYPE_FOURCC,
+ GST_STR_FOURCC ("I420"), NULL);
+ }
+ }
+
+ gst_object_unref (smokeenc);
+
+ return result;
+}
+
+static gboolean
+gst_smokeenc_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstSmokeEnc *smokeenc;
+ GstStructure *structure;
+ const GValue *framerate;
+ gboolean ret;
+ GstCaps *srccaps;
+
+ smokeenc = GST_SMOKEENC (gst_pad_get_parent (pad));
+
+ structure = gst_caps_get_structure (caps, 0);
+ framerate = gst_structure_get_value (structure, "framerate");
+ if (framerate) {
+ smokeenc->fps_num = gst_value_get_fraction_numerator (framerate);
+ smokeenc->fps_denom = gst_value_get_fraction_denominator (framerate);
+ } else {
+ smokeenc->fps_num = 0;
+ smokeenc->fps_denom = 1;
+ }
+
+ gst_structure_get_int (structure, "width", &smokeenc->width);
+ gst_structure_get_int (structure, "height", &smokeenc->height);
+
+ if ((smokeenc->width & 0x0f) != 0 || (smokeenc->height & 0x0f) != 0)
+ goto width_or_height_notx16;
+
+ if (!gst_smokeenc_resync (smokeenc))
+ goto init_failed;
+
+ srccaps = gst_caps_new_simple ("video/x-smoke",
+ "width", G_TYPE_INT, smokeenc->width,
+ "height", G_TYPE_INT, smokeenc->height,
+ "framerate", GST_TYPE_FRACTION, smokeenc->fps_num, smokeenc->fps_denom,
+ NULL);
+
+ ret = gst_pad_set_caps (smokeenc->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ gst_object_unref (smokeenc);
+
+ return ret;
+
+width_or_height_notx16:
+ {
+ GST_WARNING_OBJECT (smokeenc, "width and height must be multiples of 16"
+ ", %dx%d not allowed", smokeenc->width, smokeenc->height);
+ gst_object_unref (smokeenc);
+ return FALSE;
+ }
+init_failed:
+ {
+ GST_WARNING_OBJECT (smokeenc, "could not init decoder");
+ gst_object_unref (smokeenc);
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_smokeenc_resync (GstSmokeEnc * smokeenc)
+{
+ int ret;
+
+ GST_DEBUG ("resync: %dx%d@%d/%dfps", smokeenc->width, smokeenc->height,
+ smokeenc->fps_num, smokeenc->fps_denom);
+
+ if (smokeenc->info)
+ smokecodec_info_free (smokeenc->info);
+
+ ret = smokecodec_encode_new (&smokeenc->info, smokeenc->width,
+ smokeenc->height, smokeenc->fps_num, smokeenc->fps_denom);
+
+ if (ret != SMOKECODEC_OK)
+ goto init_failed;
+
+ smokecodec_set_quality (smokeenc->info, smokeenc->min_quality,
+ smokeenc->max_quality);
+
+ GST_DEBUG ("resync done");
+ return TRUE;
+
+ /* ERRORS */
+init_failed:
+ {
+ GST_WARNING_OBJECT (smokeenc, "smokecodec_encode_new() failed: %d", ret);
+ return FALSE;
+ }
+}
+
+static GstFlowReturn
+gst_smokeenc_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstSmokeEnc *smokeenc;
+ guchar *data, *outdata;
+ gulong size;
+ gint outsize;
+ guint encsize;
+ GstBuffer *outbuf;
+ SmokeCodecFlags flags;
+ GstFlowReturn ret;
+
+ smokeenc = GST_SMOKEENC (GST_OBJECT_PARENT (pad));
+
+ data = GST_BUFFER_DATA (buf);
+ size = GST_BUFFER_SIZE (buf);
+
+ GST_LOG_OBJECT (smokeenc, "got buffer of %lu bytes", size);
+
+ if (smokeenc->need_header) {
+ outbuf = gst_buffer_new_and_alloc (256);
+ outdata = GST_BUFFER_DATA (outbuf);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
+ GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
+
+ smokecodec_encode_id (smokeenc->info, outdata, &encsize);
+
+ GST_BUFFER_SIZE (outbuf) = encsize;
+ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smokeenc->srcpad));
+
+ ret = gst_pad_push (smokeenc->srcpad, outbuf);
+ if (ret != GST_FLOW_OK)
+ goto done;
+
+ smokeenc->need_header = FALSE;
+ }
+
+ encsize = outsize = smokeenc->width * smokeenc->height * 3;
+ outbuf = gst_buffer_new_and_alloc (outsize);
+ outdata = GST_BUFFER_DATA (outbuf);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
+ GST_BUFFER_DURATION (outbuf) =
+ gst_util_uint64_scale_int (GST_SECOND, smokeenc->fps_denom,
+ smokeenc->fps_num);
+ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smokeenc->srcpad));
+
+ flags = 0;
+ if ((smokeenc->frame % smokeenc->keyframe) == 0) {
+ flags |= SMOKECODEC_KEYFRAME;
+ }
+ smokecodec_set_quality (smokeenc->info, smokeenc->min_quality,
+ smokeenc->max_quality);
+ smokecodec_set_threshold (smokeenc->info, smokeenc->threshold);
+ smokecodec_encode (smokeenc->info, data, flags, outdata, &encsize);
+ gst_buffer_unref (buf);
+
+ GST_BUFFER_SIZE (outbuf) = encsize;
+ GST_BUFFER_OFFSET (outbuf) = smokeenc->frame;
+ GST_BUFFER_OFFSET_END (outbuf) = smokeenc->frame + 1;
+
+ ret = gst_pad_push (smokeenc->srcpad, outbuf);
+
+ smokeenc->frame++;
+
+done:
+
+ return ret;
+}
+
+static void
+gst_smokeenc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstSmokeEnc *smokeenc;
+
+ g_return_if_fail (GST_IS_SMOKEENC (object));
+ smokeenc = GST_SMOKEENC (object);
+
+ switch (prop_id) {
+ case PROP_MIN_QUALITY:
+ smokeenc->min_quality = g_value_get_int (value);
+ break;
+ case PROP_MAX_QUALITY:
+ smokeenc->max_quality = g_value_get_int (value);
+ break;
+ case PROP_THRESHOLD:
+ smokeenc->threshold = g_value_get_int (value);
+ break;
+ case PROP_KEYFRAME:
+ smokeenc->keyframe = g_value_get_int (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_smokeenc_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstSmokeEnc *smokeenc;
+
+ g_return_if_fail (GST_IS_SMOKEENC (object));
+ smokeenc = GST_SMOKEENC (object);
+
+ switch (prop_id) {
+ case PROP_MIN_QUALITY:
+ g_value_set_int (value, smokeenc->min_quality);
+ break;
+ case PROP_MAX_QUALITY:
+ g_value_set_int (value, smokeenc->max_quality);
+ break;
+ case PROP_THRESHOLD:
+ g_value_set_int (value, smokeenc->threshold);
+ break;
+ case PROP_KEYFRAME:
+ g_value_set_int (value, smokeenc->keyframe);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstStateChangeReturn
+gst_smokeenc_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstSmokeEnc *enc;
+
+ enc = GST_SMOKEENC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ /* reset the initial video state */
+ enc->width = 0;
+ enc->height = 0;
+ enc->frame = 0;
+ enc->need_header = TRUE;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret != GST_STATE_CHANGE_SUCCESS)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/ext/jpeg/gstsmokeenc.h b/ext/jpeg/gstsmokeenc.h
new file mode 100644
index 0000000..08516ff
--- /dev/null
+++ b/ext/jpeg/gstsmokeenc.h
@@ -0,0 +1,75 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_SMOKEENC_H__
+#define __GST_SMOKEENC_H__
+
+
+#include <gst/gst.h>
+#include "smokecodec.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SMOKEENC \
+ (gst_smokeenc_get_type())
+#define GST_SMOKEENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SMOKEENC,GstSmokeEnc))
+#define GST_SMOKEENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SMOKEENC,GstSmokeEncClass))
+#define GST_IS_SMOKEENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SMOKEENC))
+#define GST_IS_SMOKEENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SMOKEENC))
+
+typedef struct _GstSmokeEnc GstSmokeEnc;
+typedef struct _GstSmokeEncClass GstSmokeEncClass;
+
+struct _GstSmokeEnc {
+ GstElement element;
+
+ /* pads */
+ GstPad *sinkpad,*srcpad;
+
+ /* video state */
+ gint format;
+ gint width;
+ gint height;
+ gint frame;
+ gint keyframe;
+ gint fps_num, fps_denom;
+
+ SmokeCodecInfo *info;
+
+ gint threshold;
+ gint min_quality;
+ gint max_quality;
+
+ gboolean need_header;
+};
+
+struct _GstSmokeEncClass {
+ GstElementClass parent_class;
+};
+
+GType gst_smokeenc_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_SMOKEENC_H__ */
diff --git a/ext/jpeg/smokecodec.c b/ext/jpeg/smokecodec.c
new file mode 100644
index 0000000..98adf60
--- /dev/null
+++ b/ext/jpeg/smokecodec.c
@@ -0,0 +1,709 @@
+/* Smoke codec
+ * Copyright (C) <2004> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/* this is a hack hack hack to get around jpeglib header bugs... */
+#ifdef HAVE_STDLIB_H
+# undef HAVE_STDLIB_H
+#endif
+#include <jpeglib.h>
+
+#include "smokecodec.h"
+#include "smokeformat.h"
+
+#include <gst/gstinfo.h>
+
+struct _SmokeCodecInfo
+{
+ unsigned int width;
+ unsigned int height;
+ unsigned int fps_num;
+ unsigned int fps_denom;
+
+ unsigned int minquality;
+ unsigned int maxquality;
+ unsigned int bitrate;
+ unsigned int threshold;
+
+ unsigned int refdec;
+
+ unsigned char **line[3];
+ unsigned char *compbuf[3];
+
+ struct jpeg_error_mgr jerr;
+
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_destination_mgr jdest;
+
+ struct jpeg_decompress_struct dinfo;
+ struct jpeg_source_mgr jsrc;
+
+ int need_keyframe;
+ unsigned char *reference;
+};
+
+static void
+smokecodec_init_destination (j_compress_ptr cinfo)
+{
+}
+
+static boolean
+smokecodec_flush_destination (j_compress_ptr cinfo)
+{
+ return 1;
+}
+
+static void
+smokecodec_term_destination (j_compress_ptr cinfo)
+{
+}
+
+static void
+smokecodec_init_source (j_decompress_ptr cinfo)
+{
+}
+
+static boolean
+smokecodec_fill_input_buffer (j_decompress_ptr cinfo)
+{
+ return 1;
+}
+
+static void
+smokecodec_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+}
+
+static boolean
+smokecodec_resync_to_restart (j_decompress_ptr cinfo, int desired)
+{
+ return 1;
+}
+
+static void
+smokecodec_term_source (j_decompress_ptr cinfo)
+{
+}
+
+
+int
+smokecodec_encode_new (SmokeCodecInfo ** info,
+ const unsigned int width,
+ const unsigned int height,
+ const unsigned int fps_num, const unsigned int fps_denom)
+{
+ SmokeCodecInfo *newinfo;
+ int i, j;
+ unsigned char *base[3];
+
+ if (!info)
+ return SMOKECODEC_NULLPTR;
+ if ((width & 0xf) || (height & 0xf))
+ return SMOKECODEC_WRONGSIZE;
+
+ newinfo = malloc (sizeof (SmokeCodecInfo));
+ if (!newinfo) {
+ return SMOKECODEC_NOMEM;
+ }
+ newinfo->width = width;
+ newinfo->height = height;
+ newinfo->fps_num = fps_num;
+ newinfo->fps_denom = fps_denom;
+
+ /* setup jpeglib */
+ memset (&newinfo->cinfo, 0, sizeof (newinfo->cinfo));
+ memset (&newinfo->jerr, 0, sizeof (newinfo->jerr));
+ newinfo->cinfo.err = jpeg_std_error (&newinfo->jerr);
+ jpeg_create_compress (&newinfo->cinfo);
+ newinfo->cinfo.input_components = 3;
+ jpeg_set_defaults (&newinfo->cinfo);
+
+ newinfo->cinfo.dct_method = JDCT_FASTEST;
+
+ /* prepare for raw input */
+#if JPEG_LIB_VERSION >= 70
+ newinfo->cinfo.do_fancy_downsampling = FALSE;
+#endif
+
+ newinfo->cinfo.raw_data_in = TRUE;
+ newinfo->cinfo.in_color_space = JCS_YCbCr;
+ newinfo->cinfo.comp_info[0].h_samp_factor = 2;
+ newinfo->cinfo.comp_info[0].v_samp_factor = 2;
+ newinfo->cinfo.comp_info[1].h_samp_factor = 1;
+ newinfo->cinfo.comp_info[1].v_samp_factor = 1;
+ newinfo->cinfo.comp_info[2].h_samp_factor = 1;
+ newinfo->cinfo.comp_info[2].v_samp_factor = 1;
+
+ newinfo->line[0] = malloc (DCTSIZE * 2 * sizeof (char *));
+ newinfo->line[1] = malloc (DCTSIZE * sizeof (char *));
+ newinfo->line[2] = malloc (DCTSIZE * sizeof (char *));
+ base[0] = newinfo->compbuf[0] = malloc (256 * 2 * DCTSIZE * 2 * DCTSIZE);
+ base[1] = newinfo->compbuf[1] = malloc (256 * DCTSIZE * DCTSIZE);
+ base[2] = newinfo->compbuf[2] = malloc (256 * DCTSIZE * DCTSIZE);
+
+ for (i = 0, j = 0; i < 2 * DCTSIZE; i += 2, j++) {
+ newinfo->line[0][i] = base[0];
+ base[0] += 2 * DCTSIZE * 256;
+ newinfo->line[0][i + 1] = base[0];
+ base[0] += 2 * DCTSIZE * 256;
+ newinfo->line[1][j] = base[1];
+ base[1] += DCTSIZE * 256;
+ newinfo->line[2][j] = base[2];
+ base[2] += DCTSIZE * 256;
+ }
+
+ newinfo->jdest.init_destination = smokecodec_init_destination;
+ newinfo->jdest.empty_output_buffer = smokecodec_flush_destination;
+ newinfo->jdest.term_destination = smokecodec_term_destination;
+ newinfo->cinfo.dest = &newinfo->jdest;
+
+ jpeg_suppress_tables (&newinfo->cinfo, FALSE);
+
+ memset (&newinfo->dinfo, 0, sizeof (newinfo->dinfo));
+ newinfo->dinfo.err = jpeg_std_error (&newinfo->jerr);
+ jpeg_create_decompress (&newinfo->dinfo);
+
+ newinfo->jsrc.init_source = smokecodec_init_source;
+ newinfo->jsrc.fill_input_buffer = smokecodec_fill_input_buffer;
+ newinfo->jsrc.skip_input_data = smokecodec_skip_input_data;
+ newinfo->jsrc.resync_to_restart = smokecodec_resync_to_restart;
+ newinfo->jsrc.term_source = smokecodec_term_source;
+ newinfo->dinfo.src = &newinfo->jsrc;
+
+ newinfo->need_keyframe = 1;
+ newinfo->threshold = 4000;
+ newinfo->minquality = 10;
+ newinfo->maxquality = 85;
+ newinfo->reference = malloc (3 * (width * height) / 2);
+ newinfo->refdec = 0;
+
+ *info = newinfo;
+
+ return SMOKECODEC_OK;
+}
+
+int
+smokecodec_decode_new (SmokeCodecInfo ** info)
+{
+ return smokecodec_encode_new (info, 16, 16, 1, 1);
+}
+
+int
+smokecodec_info_free (SmokeCodecInfo * info)
+{
+ free (info->line[0]);
+ free (info->line[1]);
+ free (info->line[2]);
+ free (info->compbuf[0]);
+ free (info->compbuf[1]);
+ free (info->compbuf[2]);
+ free (info->reference);
+ jpeg_destroy_compress (&info->cinfo);
+ jpeg_destroy_decompress (&info->dinfo);
+ free (info);
+
+ return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_set_quality (SmokeCodecInfo * info,
+ const unsigned int min, const unsigned int max)
+{
+ info->minquality = min;
+ info->maxquality = max;
+
+ return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_get_quality (SmokeCodecInfo * info,
+ unsigned int *min, unsigned int *max)
+{
+ *min = info->minquality;
+ *max = info->maxquality;
+
+ return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_set_threshold (SmokeCodecInfo * info, const unsigned int threshold)
+{
+ info->threshold = threshold;
+
+ return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_get_threshold (SmokeCodecInfo * info, unsigned int *threshold)
+{
+ *threshold = info->threshold;
+
+ return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_set_bitrate (SmokeCodecInfo * info, const unsigned int bitrate)
+{
+ info->bitrate = bitrate;
+
+ return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_get_bitrate (SmokeCodecInfo * info, unsigned int *bitrate)
+{
+ *bitrate = info->bitrate;
+
+ return SMOKECODEC_OK;
+}
+
+static void
+find_best_size (int blocks, unsigned int *width, unsigned int *height)
+{
+ int sqchng;
+ int w, h;
+ int best, bestw;
+ int free;
+
+ sqchng = ceil (sqrt (blocks));
+ w = sqchng;
+ h = sqchng;
+
+ GST_DEBUG ("guess: %d %d", w, h);
+
+ free = w * h - blocks;
+ best = free;
+ bestw = w;
+
+ while (w < 256) {
+ GST_DEBUG ("current: %d %d", w, h);
+ if (free < best) {
+ best = free;
+ bestw = w;
+ if (free == 0)
+ break;
+ }
+ // if we cannot reduce the height, increase width
+ if (free < w) {
+ w++;
+ free += h;
+ }
+ // reduce height while possible
+ while (free >= w) {
+ h--;
+ free -= w;
+ }
+ }
+ *width = bestw;
+ *height = (blocks + best) / bestw;
+}
+
+static int
+abs_diff (const unsigned char *in1, const unsigned char *in2, const int stride)
+{
+ int s;
+ int i, j, diff;
+
+ s = 0;
+
+ for (i = 0; i < 2 * DCTSIZE; i++) {
+ for (j = 0; j < 2 * DCTSIZE; j++) {
+ diff = in1[j] - in2[j];
+ s += diff * diff;
+ }
+ in1 += stride;
+ in2 += stride;
+ }
+ return s;
+}
+
+static void
+put (const unsigned char *src, unsigned char *dest,
+ int width, int height, int srcstride, int deststride)
+{
+ int i, j;
+
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ dest[j] = src[j];
+ }
+ src += srcstride;
+ dest += deststride;
+ }
+}
+
+/* encoding */
+SmokeCodecResult
+smokecodec_encode_id (SmokeCodecInfo * info,
+ unsigned char *out, unsigned int *outsize)
+{
+ int i;
+
+ *out++ = SMOKECODEC_TYPE_ID;
+ for (i = 0; i < strlen (SMOKECODEC_ID_STRING); i++) {
+ *out++ = SMOKECODEC_ID_STRING[i];
+ }
+ *out++ = 0;
+ *out++ = 1;
+ *out++ = 0;
+
+ *outsize = 9;
+
+ return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_encode (SmokeCodecInfo * info,
+ const unsigned char *in,
+ SmokeCodecFlags flags, unsigned char *out, unsigned int *outsize)
+{
+ unsigned int i, j, s;
+ const unsigned char *ip;
+ unsigned char *op;
+ unsigned int blocks, encoding;
+ unsigned int size;
+ unsigned int width, height;
+ unsigned int blocks_w, blocks_h;
+ unsigned int threshold;
+ unsigned int max;
+
+ if (info->need_keyframe) {
+ flags |= SMOKECODEC_KEYFRAME;
+ info->need_keyframe = 0;
+ }
+
+ if (flags & SMOKECODEC_KEYFRAME)
+ threshold = 0;
+ else
+ threshold = info->threshold;
+
+ ip = in;
+ op = info->reference;
+
+ width = info->width;
+ height = info->height;
+
+ blocks_w = width / (DCTSIZE * 2);
+ blocks_h = height / (DCTSIZE * 2);
+
+ max = blocks_w * blocks_h;
+
+ out[IDX_TYPE] = SMOKECODEC_TYPE_DATA;
+
+#define STORE16(var, pos, x) \
+ var[pos] = (x >> 8); \
+ var[pos+1] = (x & 0xff);
+#define STORE32(var, pos, x) \
+ var[pos] = ((x >> 24) & 0xff); \
+ var[pos+1] = ((x >> 16) & 0xff); \
+ var[pos+2] = ((x >> 8) & 0xff); \
+ var[pos+3] = (x & 0xff);
+
+ /* write dimension */
+ STORE16 (out, IDX_WIDTH, width);
+ STORE16 (out, IDX_HEIGHT, height);
+
+ /* write framerate */
+ STORE32 (out, IDX_FPS_NUM, info->fps_num);
+ STORE32 (out, IDX_FPS_DENOM, info->fps_denom);
+
+ if (!(flags & SMOKECODEC_KEYFRAME)) {
+ int block = 0;
+
+ blocks = 0;
+ for (i = 0; i < height; i += 2 * DCTSIZE) {
+ for (j = 0; j < width; j += 2 * DCTSIZE) {
+ s = abs_diff (ip, op, width);
+ if (s >= threshold) {
+ STORE16 (out, blocks * 2 + IDX_BLOCKS, block);
+ blocks++;
+ }
+
+ ip += 2 * DCTSIZE;
+ op += 2 * DCTSIZE;
+ block++;
+ }
+ ip += (2 * DCTSIZE - 1) * width;
+ op += (2 * DCTSIZE - 1) * width;
+ }
+ if (blocks == max) {
+ flags |= SMOKECODEC_KEYFRAME;
+ blocks = 0;
+ encoding = max;
+ } else {
+ encoding = blocks;
+ }
+ } else {
+ blocks = 0;
+ encoding = max;
+ }
+ STORE16 (out, IDX_NUM_BLOCKS, blocks);
+ out[IDX_FLAGS] = (flags & 0xff);
+
+ GST_DEBUG ("blocks %d, encoding %d", blocks, encoding);
+
+ info->jdest.next_output_byte = &out[blocks * 2 + OFFS_PICT];
+ info->jdest.free_in_buffer = (*outsize) - OFFS_PICT;
+
+ if (encoding > 0) {
+ int quality;
+
+ if (!(flags & SMOKECODEC_KEYFRAME))
+ find_best_size (encoding, &blocks_w, &blocks_h);
+
+ GST_DEBUG ("best: %d %d", blocks_w, blocks_h);
+
+ info->cinfo.image_width = blocks_w * DCTSIZE * 2;
+ info->cinfo.image_height = blocks_h * DCTSIZE * 2;
+
+ if (flags & SMOKECODEC_KEYFRAME) {
+ quality = (info->maxquality * 60) / 100;
+ } else {
+ quality =
+ info->maxquality - ((info->maxquality -
+ info->minquality) * blocks) / max;
+ }
+
+ GST_DEBUG ("set q %d %d %d", quality, encoding, max);
+ jpeg_set_quality (&info->cinfo, quality, TRUE);
+ GST_DEBUG ("start");
+ jpeg_start_compress (&info->cinfo, TRUE);
+
+ for (i = 0; i < encoding; i++) {
+ int pos;
+ int x, y;
+
+ if (flags & SMOKECODEC_KEYFRAME)
+ pos = i;
+ else
+ pos = (out[i * 2 + IDX_BLOCKS] << 8) | (out[i * 2 + IDX_BLOCKS + 1]);
+
+ x = pos % (width / (DCTSIZE * 2));
+ y = pos / (width / (DCTSIZE * 2));
+
+ ip = in + (x * (DCTSIZE * 2)) + (y * (DCTSIZE * 2) * width);
+ op = info->compbuf[0] + (i % blocks_w) * (DCTSIZE * 2);
+ put (ip, op, 2 * DCTSIZE, 2 * DCTSIZE, width, 256 * (DCTSIZE * 2));
+
+ ip = in + width * height + (x * DCTSIZE) + (y * DCTSIZE * width / 2);
+ op = info->compbuf[1] + (i % blocks_w) * (DCTSIZE);
+ put (ip, op, DCTSIZE, DCTSIZE, width / 2, 256 * DCTSIZE);
+
+ ip = in + 5 * (width * height) / 4 + (x * DCTSIZE) +
+ (y * DCTSIZE * width / 2);
+ op = info->compbuf[2] + (i % blocks_w) * (DCTSIZE);
+ put (ip, op, DCTSIZE, DCTSIZE, width / 2, 256 * DCTSIZE);
+
+ if ((i % blocks_w) == (blocks_w - 1) || (i == encoding - 1)) {
+ GST_DEBUG ("write %d", pos);
+ jpeg_write_raw_data (&info->cinfo, info->line, 2 * DCTSIZE);
+ }
+ }
+ GST_DEBUG ("finish");
+ jpeg_finish_compress (&info->cinfo);
+ }
+
+ size = ((((*outsize) - OFFS_PICT - info->jdest.free_in_buffer) + 3) & ~3);
+ STORE16 (out, IDX_SIZE, size);
+
+ *outsize = size + blocks * 2 + OFFS_PICT;
+ GST_DEBUG ("outsize %d", *outsize);
+
+ // and decode in reference frame again
+ if (info->refdec) {
+ smokecodec_decode (info, out, *outsize, info->reference);
+ } else {
+ memcpy (info->reference, in, 3 * (width * height) / 2);
+ }
+
+ return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_parse_id (SmokeCodecInfo * info,
+ const unsigned char *in, const unsigned int insize)
+{
+ int i;
+
+ if (insize < 4 + strlen (SMOKECODEC_ID_STRING)) {
+ return SMOKECODEC_WRONGVERSION;
+ }
+
+ if (*in++ != SMOKECODEC_TYPE_ID)
+ return SMOKECODEC_ERROR;
+
+ for (i = 0; i < strlen (SMOKECODEC_ID_STRING); i++) {
+ if (*in++ != SMOKECODEC_ID_STRING[i])
+ return SMOKECODEC_ERROR;
+ }
+ if (*in++ != 0 || *in++ != 1 || *in++ != 0)
+ return SMOKECODEC_ERROR;
+
+ return SMOKECODEC_OK;
+}
+
+#define READ16(var, pos, x) \
+ x = var[pos]<<8 | var[pos+1];
+
+#define READ32(var, pos, x) \
+ x = var[pos]<<24 | var[pos+1]<<16 | \
+ var[pos+2]<<8 | var[pos+3];
+
+/* decoding */
+SmokeCodecResult
+smokecodec_parse_header (SmokeCodecInfo * info,
+ const unsigned char *in,
+ const unsigned int insize,
+ SmokeCodecFlags * flags,
+ unsigned int *width,
+ unsigned int *height, unsigned int *fps_num, unsigned int *fps_denom)
+{
+
+ READ16 (in, IDX_WIDTH, *width);
+ READ16 (in, IDX_HEIGHT, *height);
+ *flags = in[IDX_FLAGS];
+ READ32 (in, IDX_FPS_NUM, *fps_num);
+ READ32 (in, IDX_FPS_DENOM, *fps_denom);
+
+ if (info->width != *width ||
+ info->height != *height ||
+ info->fps_num != *fps_num || info->fps_denom != *fps_denom) {
+ GST_DEBUG ("new width: %d %d", *width, *height);
+
+ info->reference = realloc (info->reference, 3 * ((*width) * (*height)) / 2);
+ info->width = *width;
+ info->height = *height;
+ info->fps_num = *fps_num;
+ info->fps_denom = *fps_denom;
+ }
+
+ return SMOKECODEC_OK;
+}
+
+SmokeCodecResult
+smokecodec_decode (SmokeCodecInfo * info,
+ const unsigned char *in, const unsigned int insize, unsigned char *out)
+{
+ unsigned int width, height;
+ unsigned int fps_num, fps_denom;
+ SmokeCodecFlags flags;
+ int i, j;
+ int blocks_w, blocks_h;
+ int blockptr;
+ int blocks, decoding;
+ const unsigned char *ip;
+ unsigned char *op;
+ int res;
+
+ smokecodec_parse_header (info, in, insize, &flags, &width, &height,
+ &fps_num, &fps_denom);
+
+ READ16 (in, IDX_NUM_BLOCKS, blocks);
+ GST_DEBUG ("blocks %d", blocks);
+
+ if (flags & SMOKECODEC_KEYFRAME)
+ decoding = width / (DCTSIZE * 2) * height / (DCTSIZE * 2);
+ else
+ decoding = blocks;
+
+ if (decoding > 0) {
+ info->jsrc.next_input_byte = &in[blocks * 2 + OFFS_PICT];
+ info->jsrc.bytes_in_buffer = insize - (blocks * 2 + OFFS_PICT);
+
+ GST_DEBUG ("header %02x %d", in[blocks * 2 + OFFS_PICT], insize);
+ res = jpeg_read_header (&info->dinfo, TRUE);
+ GST_DEBUG ("header %d %d %d", res, info->dinfo.image_width,
+ info->dinfo.image_height);
+
+ blocks_w = info->dinfo.image_width / (2 * DCTSIZE);
+ blocks_h = info->dinfo.image_height / (2 * DCTSIZE);
+
+ info->dinfo.output_width = info->dinfo.image_width;
+ info->dinfo.output_height = info->dinfo.image_height;
+
+ GST_DEBUG ("start");
+ info->dinfo.do_fancy_upsampling = FALSE;
+ info->dinfo.do_block_smoothing = FALSE;
+ info->dinfo.out_color_space = JCS_YCbCr;
+ info->dinfo.dct_method = JDCT_IFAST;
+ info->dinfo.raw_data_out = TRUE;
+ jpeg_start_decompress (&info->dinfo);
+
+ blockptr = 0;
+
+ for (i = 0; i < blocks_h; i++) {
+ GST_DEBUG ("read");
+ jpeg_read_raw_data (&info->dinfo, info->line, 2 * DCTSIZE);
+
+ GST_DEBUG ("copy %d", blocks_w);
+ for (j = 0; j < blocks_w; j++) {
+ int pos;
+ int x, y;
+
+ if (flags & SMOKECODEC_KEYFRAME)
+ pos = blockptr;
+ else
+ READ16 (in, blockptr * 2 + IDX_BLOCKS, pos);
+
+ x = pos % (width / (DCTSIZE * 2));
+ y = pos / (width / (DCTSIZE * 2));
+
+ GST_DEBUG ("block %d %d %d", pos, x, y);
+
+ ip = info->compbuf[0] + j * (DCTSIZE * 2);
+ op = info->reference + (x * (DCTSIZE * 2)) +
+ (y * (DCTSIZE * 2) * width);
+ put (ip, op, 2 * DCTSIZE, 2 * DCTSIZE, 256 * (DCTSIZE * 2), width);
+
+ ip = info->compbuf[1] + j * (DCTSIZE);
+ op = info->reference + width * height + (x * DCTSIZE) +
+ (y * DCTSIZE * width / 2);
+ put (ip, op, DCTSIZE, DCTSIZE, 256 * DCTSIZE, width / 2);
+
+ ip = info->compbuf[2] + j * (DCTSIZE);
+ op = info->reference + 5 * (width * height) / 4 + (x * DCTSIZE) +
+ (y * DCTSIZE * width / 2);
+ put (ip, op, DCTSIZE, DCTSIZE, 256 * DCTSIZE, width / 2);
+
+ GST_DEBUG ("block done %d %d %d", pos, x, y);
+ blockptr++;
+ if (blockptr >= decoding)
+ break;
+ }
+ }
+ GST_DEBUG ("finish");
+ jpeg_finish_decompress (&info->dinfo);
+ }
+
+ GST_DEBUG ("copy");
+ if (out != info->reference)
+ memcpy (out, info->reference, 3 * (width * height) / 2);
+ GST_DEBUG ("copy done");
+
+ return SMOKECODEC_OK;
+}
diff --git a/ext/jpeg/smokecodec.h b/ext/jpeg/smokecodec.h
new file mode 100644
index 0000000..a44d9bb
--- /dev/null
+++ b/ext/jpeg/smokecodec.h
@@ -0,0 +1,119 @@
+/* Smoke Codec
+ * Copyright (C) <2004> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __SMOKECODEC_H__
+#define __SMOKECODEC_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+typedef struct _SmokeCodecInfo SmokeCodecInfo;
+
+typedef enum {
+ SMOKECODEC_WRONGVERSION = -5,
+ SMOKECODEC_WRONGSIZE = -4,
+ SMOKECODEC_ERROR = -3,
+ SMOKECODEC_NOMEM = -2,
+ SMOKECODEC_NULLPTR = -1,
+ SMOKECODEC_OK = 0
+} SmokeCodecResult;
+
+typedef enum {
+ SMOKECODEC_KEYFRAME = (1<<0),
+ SMOKECODEC_MOTION_VECTORS = (1<<1)
+} SmokeCodecFlags;
+
+#define SMOKECODEC_ID_STRING "smoke"
+
+typedef enum {
+ SMOKECODEC_TYPE_ID = 0x80,
+ SMOKECODEC_TYPE_COMMENT = 0x81,
+ SMOKECODEC_TYPE_EXTRA = 0x83,
+ SMOKECODEC_TYPE_DATA = 0x40
+} SmokePacketType;
+
+/* init */
+int smokecodec_encode_new (SmokeCodecInfo **info,
+ const unsigned int width,
+ const unsigned int height,
+ const unsigned int fps_num,
+ const unsigned int fps_denom);
+
+int smokecodec_decode_new (SmokeCodecInfo **info);
+
+int smokecodec_info_free (SmokeCodecInfo * info);
+
+/* config */
+SmokeCodecResult smokecodec_set_quality (SmokeCodecInfo *info,
+ const unsigned int min,
+ const unsigned int max);
+SmokeCodecResult smokecodec_get_quality (SmokeCodecInfo *info,
+ unsigned int *min,
+ unsigned int *max);
+
+SmokeCodecResult smokecodec_set_threshold (SmokeCodecInfo *info,
+ const unsigned int threshold);
+SmokeCodecResult smokecodec_get_threshold (SmokeCodecInfo *info,
+ unsigned int *threshold);
+
+SmokeCodecResult smokecodec_set_bitrate (SmokeCodecInfo *info,
+ const unsigned int bitrate);
+SmokeCodecResult smokecodec_get_bitrate (SmokeCodecInfo *info,
+ unsigned int *bitrate);
+
+/* encoding */
+SmokeCodecResult smokecodec_encode_id (SmokeCodecInfo *info,
+ unsigned char *out,
+ unsigned int *outsize);
+
+SmokeCodecResult smokecodec_encode (SmokeCodecInfo *info,
+ const unsigned char *in,
+ SmokeCodecFlags flags,
+ unsigned char *out,
+ unsigned int *outsize);
+
+/* decoding */
+SmokeCodecResult smokecodec_parse_id (SmokeCodecInfo *info,
+ const unsigned char *in,
+ const unsigned int insize);
+
+SmokeCodecResult smokecodec_parse_header (SmokeCodecInfo *info,
+ const unsigned char *in,
+ const unsigned int insize,
+ SmokeCodecFlags *flags,
+ unsigned int *width,
+ unsigned int *height,
+ unsigned int *fps_num,
+ unsigned int *fps_denom);
+
+SmokeCodecResult smokecodec_decode (SmokeCodecInfo *info,
+ const unsigned char *in,
+ const unsigned int insize,
+ unsigned char *out);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __SMOKECODEC_H__ */
diff --git a/ext/jpeg/smokeformat.h b/ext/jpeg/smokeformat.h
new file mode 100644
index 0000000..1511934
--- /dev/null
+++ b/ext/jpeg/smokeformat.h
@@ -0,0 +1,46 @@
+/* Smoke Codec
+ * Copyright (C) <2004> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __SMOKEFORMAT_H__
+#define __SMOKEFORMAT_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define IDX_TYPE 0
+#define IDX_WIDTH 1
+#define IDX_HEIGHT 3
+#define IDX_FPS_NUM 5
+#define IDX_FPS_DENOM 9
+#define IDX_FLAGS 13
+#define IDX_NUM_BLOCKS 14
+#define IDX_SIZE 16
+#define IDX_BLOCKS 18
+#define OFFS_PICT 18
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __SMOKEFORMAT_H__ */
diff --git a/ext/libcaca/Makefile.am b/ext/libcaca/Makefile.am
new file mode 100644
index 0000000..e44c048
--- /dev/null
+++ b/ext/libcaca/Makefile.am
@@ -0,0 +1,16 @@
+plugin_LTLIBRARIES = libgstcacasink.la
+
+libgstcacasink_la_SOURCES = gstcacasink.c
+libgstcacasink_la_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) \
+ $(LIBCACA_CFLAGS)
+libgstcacasink_la_LIBADD = \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS) \
+ $(LIBCACA_LIBS)
+libgstcacasink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstcacasink_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstcacasink.h
diff --git a/ext/libcaca/Makefile.in b/ext/libcaca/Makefile.in
new file mode 100644
index 0000000..d12e274
--- /dev/null
+++ b/ext/libcaca/Makefile.in
@@ -0,0 +1,814 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/libcaca
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstcacasink_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libgstcacasink_la_OBJECTS = libgstcacasink_la-gstcacasink.lo
+libgstcacasink_la_OBJECTS = $(am_libgstcacasink_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstcacasink_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstcacasink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstcacasink_la_CFLAGS) $(CFLAGS) \
+ $(libgstcacasink_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstcacasink_la_SOURCES)
+DIST_SOURCES = $(libgstcacasink_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstcacasink.la
+libgstcacasink_la_SOURCES = gstcacasink.c
+libgstcacasink_la_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) \
+ $(LIBCACA_CFLAGS)
+
+libgstcacasink_la_LIBADD = \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS) \
+ $(LIBCACA_LIBS)
+
+libgstcacasink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstcacasink_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = gstcacasink.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/libcaca/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/libcaca/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstcacasink.la: $(libgstcacasink_la_OBJECTS) $(libgstcacasink_la_DEPENDENCIES) $(EXTRA_libgstcacasink_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstcacasink_la_LINK) -rpath $(plugindir) $(libgstcacasink_la_OBJECTS) $(libgstcacasink_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstcacasink_la-gstcacasink.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstcacasink_la-gstcacasink.lo: gstcacasink.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcacasink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcacasink_la_CFLAGS) $(CFLAGS) -MT libgstcacasink_la-gstcacasink.lo -MD -MP -MF $(DEPDIR)/libgstcacasink_la-gstcacasink.Tpo -c -o libgstcacasink_la-gstcacasink.lo `test -f 'gstcacasink.c' || echo '$(srcdir)/'`gstcacasink.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstcacasink_la-gstcacasink.Tpo $(DEPDIR)/libgstcacasink_la-gstcacasink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstcacasink.c' object='libgstcacasink_la-gstcacasink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstcacasink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstcacasink_la_CFLAGS) $(CFLAGS) -c -o libgstcacasink_la-gstcacasink.lo `test -f 'gstcacasink.c' || echo '$(srcdir)/'`gstcacasink.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/libcaca/gstcacasink.c b/ext/libcaca/gstcacasink.c
new file mode 100644
index 0000000..5c3a589
--- /dev/null
+++ b/ext/libcaca/gstcacasink.c
@@ -0,0 +1,426 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:element-cacasink
+ * @see_also: #GstAASink
+ *
+ * Displays video as color ascii art.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * CACA_GEOMETRY=160x60 CACA_FONT=5x7 gst-launch filesrc location=test.avi ! decodebin ! ffmpegcolorspace ! cacasink
+ * ]| This pipeline renders a video to ascii art into a separate window using a
+ * small font and specifying the ascii resolution.
+ * |[
+ * CACA_DRIVER=ncurses gst-launch filesrc location=test.avi ! decodebin ! ffmpegcolorspace ! cacasink
+ * ]| This pipeline renders a video to ascii art into the current terminal.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <sys/time.h>
+
+#include "gstcacasink.h"
+
+#define GST_CACA_DEFAULT_SCREEN_WIDTH 80
+#define GST_CACA_DEFAULT_SCREEN_HEIGHT 25
+#define GST_CACA_DEFAULT_BPP 24
+#define GST_CACA_DEFAULT_RED_MASK GST_VIDEO_BYTE1_MASK_32_INT
+#define GST_CACA_DEFAULT_GREEN_MASK GST_VIDEO_BYTE2_MASK_32_INT
+#define GST_CACA_DEFAULT_BLUE_MASK GST_VIDEO_BYTE3_MASK_32_INT
+
+//#define GST_CACA_DEFAULT_RED_MASK R_MASK_32_REVERSE_INT
+//#define GST_CACA_DEFAULT_GREEN_MASK G_MASK_32_REVERSE_INT
+//#define GST_CACA_DEFAULT_BLUE_MASK B_MASK_32_REVERSE_INT
+
+/* cacasink signals and args */
+enum
+{
+ LAST_SIGNAL
+};
+
+
+enum
+{
+ ARG_0,
+ ARG_SCREEN_WIDTH,
+ ARG_SCREEN_HEIGHT,
+ ARG_DITHER,
+ ARG_ANTIALIASING
+};
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_RGBx ";"
+ GST_VIDEO_CAPS_RGB_16 ";" GST_VIDEO_CAPS_RGB_15)
+ );
+
+static void gst_cacasink_base_init (gpointer g_class);
+static void gst_cacasink_class_init (GstCACASinkClass * klass);
+static void gst_cacasink_init (GstCACASink * cacasink);
+
+static gboolean gst_cacasink_setcaps (GstBaseSink * pad, GstCaps * caps);
+static void gst_cacasink_get_times (GstBaseSink * sink, GstBuffer * buffer,
+ GstClockTime * start, GstClockTime * end);
+static GstFlowReturn gst_cacasink_render (GstBaseSink * basesink,
+ GstBuffer * buffer);
+
+static void gst_cacasink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_cacasink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn gst_cacasink_change_state (GstElement * element,
+ GstStateChange transition);
+
+static GstElementClass *parent_class = NULL;
+
+GType
+gst_cacasink_get_type (void)
+{
+ static GType cacasink_type = 0;
+
+ if (!cacasink_type) {
+ static const GTypeInfo cacasink_info = {
+ sizeof (GstCACASinkClass),
+ gst_cacasink_base_init,
+ NULL,
+ (GClassInitFunc) gst_cacasink_class_init,
+ NULL,
+ NULL,
+ sizeof (GstCACASink),
+ 0,
+ (GInstanceInitFunc) gst_cacasink_init,
+ };
+
+ cacasink_type =
+ g_type_register_static (GST_TYPE_BASE_SINK, "GstCACASink",
+ &cacasink_info, 0);
+ }
+ return cacasink_type;
+}
+
+#define GST_TYPE_CACADITHER (gst_cacasink_dither_get_type())
+static GType
+gst_cacasink_dither_get_type (void)
+{
+ static GType dither_type = 0;
+
+ static const GEnumValue dither_types[] = {
+ {CACA_DITHERING_NONE, "No dithering", "none"},
+ {CACA_DITHERING_ORDERED2, "Ordered 2x2 Bayer dithering", "2x2"},
+ {CACA_DITHERING_ORDERED4, "Ordered 4x4 Bayer dithering", "4x4"},
+ {CACA_DITHERING_ORDERED8, "Ordered 8x8 Bayer dithering", "8x8"},
+ {CACA_DITHERING_RANDOM, "Random dithering", "random"},
+ {0, NULL, NULL},
+ };
+
+ if (!dither_type) {
+ dither_type = g_enum_register_static ("GstCACASinkDithering", dither_types);
+ }
+ return dither_type;
+}
+
+static void
+gst_cacasink_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details_simple (element_class,
+ "A colored ASCII art video sink", "Sink/Video",
+ "A colored ASCII art videosink", "Zeeshan Ali <zak147@yahoo.com>");
+ gst_element_class_add_static_pad_template (element_class,
+ &sink_template);
+}
+
+static void
+gst_cacasink_class_init (GstCACASinkClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstBaseSinkClass *gstbasesink_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstbasesink_class = (GstBaseSinkClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->set_property = gst_cacasink_set_property;
+ gobject_class->get_property = gst_cacasink_get_property;
+ gstelement_class->change_state = gst_cacasink_change_state;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SCREEN_WIDTH,
+ g_param_spec_int ("screen-width", "Screen Width",
+ "The width of the screen", 0, G_MAXINT, GST_CACA_DEFAULT_SCREEN_WIDTH,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SCREEN_HEIGHT,
+ g_param_spec_int ("screen-height", "Screen Height",
+ "The height of the screen", 0, G_MAXINT,
+ GST_CACA_DEFAULT_SCREEN_HEIGHT,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DITHER,
+ g_param_spec_enum ("dither", "Dither Type", "Set type of Dither",
+ GST_TYPE_CACADITHER, CACA_DITHERING_NONE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ANTIALIASING,
+ g_param_spec_boolean ("anti-aliasing", "Anti Aliasing",
+ "Enables Anti-Aliasing", TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_cacasink_setcaps);
+ gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_cacasink_get_times);
+ gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_cacasink_render);
+ gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_cacasink_render);
+}
+
+static void
+gst_cacasink_get_times (GstBaseSink * sink, GstBuffer * buffer,
+ GstClockTime * start, GstClockTime * end)
+{
+ *start = GST_BUFFER_TIMESTAMP (buffer);
+ *end = *start + GST_BUFFER_DURATION (buffer);
+}
+
+static gboolean
+gst_cacasink_setcaps (GstBaseSink * basesink, GstCaps * caps)
+{
+ GstCACASink *cacasink;
+ GstStructure *structure;
+ gint endianness;
+
+ cacasink = GST_CACASINK (basesink);
+
+ structure = gst_caps_get_structure (caps, 0);
+ gst_structure_get_int (structure, "width", &(cacasink->width));
+ gst_structure_get_int (structure, "height", &(cacasink->height));
+ gst_structure_get_int (structure, "endianness", &endianness);
+ gst_structure_get_int (structure, "bpp", (int *) &cacasink->bpp);
+ gst_structure_get_int (structure, "red_mask", (int *) &cacasink->red_mask);
+ gst_structure_get_int (structure, "green_mask",
+ (int *) &cacasink->green_mask);
+ gst_structure_get_int (structure, "blue_mask", (int *) &cacasink->blue_mask);
+
+ if (cacasink->bpp == 24) {
+ cacasink->red_mask = GUINT32_FROM_BE (cacasink->red_mask) >> 8;
+ cacasink->green_mask = GUINT32_FROM_BE (cacasink->green_mask) >> 8;
+ cacasink->blue_mask = GUINT32_FROM_BE (cacasink->blue_mask) >> 8;
+ }
+
+ else if (cacasink->bpp == 32) {
+ cacasink->red_mask = GUINT32_FROM_BE (cacasink->red_mask);
+ cacasink->green_mask = GUINT32_FROM_BE (cacasink->green_mask);
+ cacasink->blue_mask = GUINT32_FROM_BE (cacasink->blue_mask);
+ }
+
+ else if (cacasink->bpp == 16) {
+ if (endianness == G_BIG_ENDIAN) {
+ cacasink->red_mask = GUINT16_FROM_BE (cacasink->red_mask);
+ cacasink->green_mask = GUINT16_FROM_BE (cacasink->green_mask);
+ cacasink->blue_mask = GUINT16_FROM_BE (cacasink->blue_mask);
+ } else {
+ cacasink->red_mask = GUINT16_FROM_LE (cacasink->red_mask);
+ cacasink->green_mask = GUINT16_FROM_LE (cacasink->green_mask);
+ cacasink->blue_mask = GUINT16_FROM_LE (cacasink->blue_mask);
+ }
+ }
+
+ if (cacasink->bitmap) {
+ caca_free_bitmap (cacasink->bitmap);
+ }
+
+ cacasink->bitmap = caca_create_bitmap (cacasink->bpp,
+ cacasink->width,
+ cacasink->height,
+ GST_ROUND_UP_4 (cacasink->width * cacasink->bpp / 8),
+ cacasink->red_mask, cacasink->green_mask, cacasink->blue_mask, 0);
+
+ if (!cacasink->bitmap) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+gst_cacasink_init (GstCACASink * cacasink)
+{
+ cacasink->screen_width = GST_CACA_DEFAULT_SCREEN_WIDTH;
+ cacasink->screen_height = GST_CACA_DEFAULT_SCREEN_HEIGHT;
+ cacasink->bpp = GST_CACA_DEFAULT_BPP;
+ cacasink->red_mask = GST_CACA_DEFAULT_RED_MASK;
+ cacasink->green_mask = GST_CACA_DEFAULT_GREEN_MASK;
+ cacasink->blue_mask = GST_CACA_DEFAULT_BLUE_MASK;
+}
+
+static GstFlowReturn
+gst_cacasink_render (GstBaseSink * basesink, GstBuffer * buffer)
+{
+ GstCACASink *cacasink = GST_CACASINK (basesink);
+
+ GST_DEBUG ("render");
+
+ caca_clear ();
+ caca_draw_bitmap (0, 0, cacasink->screen_width - 1,
+ cacasink->screen_height - 1, cacasink->bitmap, GST_BUFFER_DATA (buffer));
+ caca_refresh ();
+
+ return GST_FLOW_OK;
+}
+
+static void
+gst_cacasink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstCACASink *cacasink;
+
+ g_return_if_fail (GST_IS_CACASINK (object));
+
+ cacasink = GST_CACASINK (object);
+
+ switch (prop_id) {
+ case ARG_DITHER:{
+ cacasink->dither = g_value_get_enum (value);
+ caca_set_dithering (cacasink->dither + CACA_DITHERING_NONE);
+ break;
+ }
+ case ARG_ANTIALIASING:{
+ cacasink->antialiasing = g_value_get_boolean (value);
+ if (cacasink->antialiasing) {
+ caca_set_feature (CACA_ANTIALIASING_MAX);
+ } else {
+ caca_set_feature (CACA_ANTIALIASING_MIN);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void
+gst_cacasink_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstCACASink *cacasink;
+
+ cacasink = GST_CACASINK (object);
+
+ switch (prop_id) {
+ case ARG_SCREEN_WIDTH:{
+ g_value_set_int (value, cacasink->screen_width);
+ break;
+ }
+ case ARG_SCREEN_HEIGHT:{
+ g_value_set_int (value, cacasink->screen_height);
+ break;
+ }
+ case ARG_DITHER:{
+ g_value_set_enum (value, cacasink->dither);
+ break;
+ }
+ case ARG_ANTIALIASING:{
+ g_value_set_boolean (value, cacasink->antialiasing);
+ break;
+ }
+ default:{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ }
+}
+
+static gboolean
+gst_cacasink_open (GstCACASink * cacasink)
+{
+ cacasink->bitmap = NULL;
+
+ if (caca_init () < 0) {
+ GST_ELEMENT_ERROR (cacasink, RESOURCE, OPEN_WRITE, (NULL),
+ ("caca_init() failed"));
+ return FALSE;
+ }
+
+ cacasink->screen_width = caca_get_width ();
+ cacasink->screen_height = caca_get_height ();
+ cacasink->antialiasing = TRUE;
+ caca_set_feature (CACA_ANTIALIASING_MAX);
+ cacasink->dither = 0;
+ caca_set_dithering (CACA_DITHERING_NONE);
+
+ return TRUE;
+}
+
+static void
+gst_cacasink_close (GstCACASink * cacasink)
+{
+ if (cacasink->bitmap) {
+ caca_free_bitmap (cacasink->bitmap);
+ cacasink->bitmap = NULL;
+ }
+ caca_end ();
+}
+
+static GstStateChangeReturn
+gst_cacasink_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ if (!gst_cacasink_open (GST_CACASINK (element)))
+ return GST_STATE_CHANGE_FAILURE;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_cacasink_close (GST_CACASINK (element));
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "cacasink", GST_RANK_NONE,
+ GST_TYPE_CACASINK))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "cacasink",
+ "Colored ASCII Art video sink",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/libcaca/gstcacasink.h b/ext/libcaca/gstcacasink.h
new file mode 100644
index 0000000..580567a
--- /dev/null
+++ b/ext/libcaca/gstcacasink.h
@@ -0,0 +1,72 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_CACASINK_H__
+#define __GST_CACASINK_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+#include <gst/video/video.h>
+
+#include <caca.h>
+#ifdef CACA_API_VERSION_1
+# include <caca0.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CACASINK \
+ (gst_cacasink_get_type())
+#define GST_CACASINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CACASINK,GstCACASink))
+#define GST_CACASINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CACASINK,GstCACASinkClass))
+#define GST_IS_CACASINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CACASINK))
+#define GST_IS_CACASINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CACASINK))
+
+typedef struct _GstCACASink GstCACASink;
+typedef struct _GstCACASinkClass GstCACASinkClass;
+
+struct _GstCACASink {
+ GstBaseSink parent;
+
+ gint width, height;
+ gint screen_width, screen_height;
+ guint bpp;
+ guint dither;
+ gboolean antialiasing;
+ guint red_mask, green_mask, blue_mask;
+
+ struct caca_bitmap *bitmap;
+};
+
+struct _GstCACASinkClass {
+ GstBaseSinkClass parent_class;
+
+ /* signals */
+};
+
+GType gst_cacasink_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_CACASINK_H__ */
diff --git a/ext/libpng/Makefile.am b/ext/libpng/Makefile.am
new file mode 100644
index 0000000..bce5b1a
--- /dev/null
+++ b/ext/libpng/Makefile.am
@@ -0,0 +1,10 @@
+plugin_LTLIBRARIES = libgstpng.la
+
+libgstpng_la_SOURCES = gstpng.c gstpngenc.c gstpngdec.c
+libgstpng_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LIBPNG_CFLAGS)
+libgstpng_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_MAJORMINOR@ \
+ $(GST_LIBS) $(LIBPNG_LIBS)
+libgstpng_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstpng_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstpngdec.h gstpngenc.h
diff --git a/ext/libpng/Makefile.in b/ext/libpng/Makefile.in
new file mode 100644
index 0000000..960a341
--- /dev/null
+++ b/ext/libpng/Makefile.in
@@ -0,0 +1,824 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/libpng
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstpng_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libgstpng_la_OBJECTS = libgstpng_la-gstpng.lo \
+ libgstpng_la-gstpngenc.lo libgstpng_la-gstpngdec.lo
+libgstpng_la_OBJECTS = $(am_libgstpng_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstpng_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstpng_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstpng_la_CFLAGS) $(CFLAGS) \
+ $(libgstpng_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstpng_la_SOURCES)
+DIST_SOURCES = $(libgstpng_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstpng.la
+libgstpng_la_SOURCES = gstpng.c gstpngenc.c gstpngdec.c
+libgstpng_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LIBPNG_CFLAGS)
+libgstpng_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_MAJORMINOR@ \
+ $(GST_LIBS) $(LIBPNG_LIBS)
+
+libgstpng_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstpng_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = gstpngdec.h gstpngenc.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/libpng/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/libpng/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstpng.la: $(libgstpng_la_OBJECTS) $(libgstpng_la_DEPENDENCIES) $(EXTRA_libgstpng_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstpng_la_LINK) -rpath $(plugindir) $(libgstpng_la_OBJECTS) $(libgstpng_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstpng_la-gstpng.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstpng_la-gstpngdec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstpng_la-gstpngenc.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstpng_la-gstpng.lo: gstpng.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpng_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpng_la_CFLAGS) $(CFLAGS) -MT libgstpng_la-gstpng.lo -MD -MP -MF $(DEPDIR)/libgstpng_la-gstpng.Tpo -c -o libgstpng_la-gstpng.lo `test -f 'gstpng.c' || echo '$(srcdir)/'`gstpng.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstpng_la-gstpng.Tpo $(DEPDIR)/libgstpng_la-gstpng.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstpng.c' object='libgstpng_la-gstpng.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpng_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpng_la_CFLAGS) $(CFLAGS) -c -o libgstpng_la-gstpng.lo `test -f 'gstpng.c' || echo '$(srcdir)/'`gstpng.c
+
+libgstpng_la-gstpngenc.lo: gstpngenc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpng_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpng_la_CFLAGS) $(CFLAGS) -MT libgstpng_la-gstpngenc.lo -MD -MP -MF $(DEPDIR)/libgstpng_la-gstpngenc.Tpo -c -o libgstpng_la-gstpngenc.lo `test -f 'gstpngenc.c' || echo '$(srcdir)/'`gstpngenc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstpng_la-gstpngenc.Tpo $(DEPDIR)/libgstpng_la-gstpngenc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstpngenc.c' object='libgstpng_la-gstpngenc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpng_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpng_la_CFLAGS) $(CFLAGS) -c -o libgstpng_la-gstpngenc.lo `test -f 'gstpngenc.c' || echo '$(srcdir)/'`gstpngenc.c
+
+libgstpng_la-gstpngdec.lo: gstpngdec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpng_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpng_la_CFLAGS) $(CFLAGS) -MT libgstpng_la-gstpngdec.lo -MD -MP -MF $(DEPDIR)/libgstpng_la-gstpngdec.Tpo -c -o libgstpng_la-gstpngdec.lo `test -f 'gstpngdec.c' || echo '$(srcdir)/'`gstpngdec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstpng_la-gstpngdec.Tpo $(DEPDIR)/libgstpng_la-gstpngdec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstpngdec.c' object='libgstpng_la-gstpngdec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpng_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpng_la_CFLAGS) $(CFLAGS) -c -o libgstpng_la-gstpngdec.lo `test -f 'gstpngdec.c' || echo '$(srcdir)/'`gstpngdec.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/libpng/gstpng.c b/ext/libpng/gstpng.c
new file mode 100644
index 0000000..6a91915
--- /dev/null
+++ b/ext/libpng/gstpng.c
@@ -0,0 +1,47 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * Filter:
+ * Copyright (C) 2000 Donald A. Graft
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <gst/gst.h>
+
+#include "gstpngdec.h"
+#include "gstpngenc.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "pngdec", GST_RANK_PRIMARY,
+ GST_TYPE_PNGDEC))
+ return FALSE;
+
+ if (!gst_element_register (plugin, "pngenc", GST_RANK_PRIMARY,
+ GST_TYPE_PNGENC))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "png",
+ "PNG plugin library", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
+ GST_PACKAGE_ORIGIN)
diff --git a/ext/libpng/gstpngdec.c b/ext/libpng/gstpngdec.c
new file mode 100644
index 0000000..4a2b547
--- /dev/null
+++ b/ext/libpng/gstpngdec.c
@@ -0,0 +1,898 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+/**
+ * SECTION:element-pngdec
+ *
+ * Decodes png images. If there is no framerate set on sink caps, it sends EOS
+ * after the first picture.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstpngdec.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/video/video.h>
+#include <gst/gst-i18n-plugin.h>
+
+GST_DEBUG_CATEGORY_STATIC (pngdec_debug);
+#define GST_CAT_DEFAULT pngdec_debug
+
+static void gst_pngdec_base_init (gpointer g_class);
+static void gst_pngdec_class_init (GstPngDecClass * klass);
+static void gst_pngdec_init (GstPngDec * pngdec);
+
+static gboolean gst_pngdec_libpng_init (GstPngDec * pngdec);
+static gboolean gst_pngdec_libpng_clear (GstPngDec * pngdec);
+
+static GstStateChangeReturn gst_pngdec_change_state (GstElement * element,
+ GstStateChange transition);
+
+static gboolean gst_pngdec_sink_activate_push (GstPad * sinkpad,
+ gboolean active);
+static gboolean gst_pngdec_sink_activate_pull (GstPad * sinkpad,
+ gboolean active);
+static gboolean gst_pngdec_sink_activate (GstPad * sinkpad);
+
+static GstFlowReturn gst_pngdec_caps_create_and_set (GstPngDec * pngdec);
+
+static void gst_pngdec_task (GstPad * pad);
+static GstFlowReturn gst_pngdec_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_pngdec_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_pngdec_sink_setcaps (GstPad * pad, GstCaps * caps);
+
+static GstElementClass *parent_class = NULL;
+
+GType
+gst_pngdec_get_type (void)
+{
+ static GType pngdec_type = 0;
+
+ if (!pngdec_type) {
+ static const GTypeInfo pngdec_info = {
+ sizeof (GstPngDecClass),
+ gst_pngdec_base_init,
+ NULL,
+ (GClassInitFunc) gst_pngdec_class_init,
+ NULL,
+ NULL,
+ sizeof (GstPngDec),
+ 0,
+ (GInstanceInitFunc) gst_pngdec_init,
+ };
+
+ pngdec_type = g_type_register_static (GST_TYPE_ELEMENT, "GstPngDec",
+ &pngdec_info, 0);
+ }
+ return pngdec_type;
+}
+
+static GstStaticPadTemplate gst_pngdec_src_pad_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_RGB ";"
+ GST_VIDEO_CAPS_ARGB_64)
+ );
+
+static GstStaticPadTemplate gst_pngdec_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("image/png")
+ );
+
+static void
+gst_pngdec_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_pngdec_src_pad_template);
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_pngdec_sink_pad_template);
+ gst_element_class_set_details_simple (element_class, "PNG image decoder",
+ "Codec/Decoder/Image",
+ "Decode a png video frame to a raw image",
+ "Wim Taymans <wim@fluendo.com>");
+}
+
+static void
+gst_pngdec_class_init (GstPngDecClass * klass)
+{
+ GstElementClass *gstelement_class;
+
+ gstelement_class = (GstElementClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gstelement_class->change_state = gst_pngdec_change_state;
+
+ GST_DEBUG_CATEGORY_INIT (pngdec_debug, "pngdec", 0, "PNG image decoder");
+}
+
+static void
+gst_pngdec_init (GstPngDec * pngdec)
+{
+ pngdec->sinkpad =
+ gst_pad_new_from_static_template (&gst_pngdec_sink_pad_template, "sink");
+ gst_pad_set_activate_function (pngdec->sinkpad, gst_pngdec_sink_activate);
+ gst_pad_set_activatepush_function (pngdec->sinkpad,
+ gst_pngdec_sink_activate_push);
+ gst_pad_set_activatepull_function (pngdec->sinkpad,
+ gst_pngdec_sink_activate_pull);
+ gst_pad_set_chain_function (pngdec->sinkpad, gst_pngdec_chain);
+ gst_pad_set_event_function (pngdec->sinkpad, gst_pngdec_sink_event);
+ gst_pad_set_setcaps_function (pngdec->sinkpad, gst_pngdec_sink_setcaps);
+ gst_element_add_pad (GST_ELEMENT (pngdec), pngdec->sinkpad);
+
+ pngdec->srcpad =
+ gst_pad_new_from_static_template (&gst_pngdec_src_pad_template, "src");
+ gst_pad_use_fixed_caps (pngdec->srcpad);
+ gst_element_add_pad (GST_ELEMENT (pngdec), pngdec->srcpad);
+
+ pngdec->buffer_out = NULL;
+ pngdec->png = NULL;
+ pngdec->info = NULL;
+ pngdec->endinfo = NULL;
+ pngdec->setup = FALSE;
+
+ pngdec->color_type = -1;
+ pngdec->width = -1;
+ pngdec->height = -1;
+ pngdec->bpp = -1;
+ pngdec->fps_n = 0;
+ pngdec->fps_d = 1;
+
+ pngdec->in_timestamp = GST_CLOCK_TIME_NONE;
+ pngdec->in_duration = GST_CLOCK_TIME_NONE;
+
+ gst_segment_init (&pngdec->segment, GST_FORMAT_UNDEFINED);
+
+ pngdec->image_ready = FALSE;
+}
+
+static void
+user_error_fn (png_structp png_ptr, png_const_charp error_msg)
+{
+ GST_ERROR ("%s", error_msg);
+}
+
+static void
+user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
+{
+ GST_WARNING ("%s", warning_msg);
+}
+
+static void
+user_info_callback (png_structp png_ptr, png_infop info)
+{
+ GstPngDec *pngdec = NULL;
+ GstFlowReturn ret = GST_FLOW_OK;
+ size_t buffer_size;
+ GstBuffer *buffer = NULL;
+
+ pngdec = GST_PNGDEC (png_get_io_ptr (png_ptr));
+
+ GST_LOG ("info ready");
+
+ /* Generate the caps and configure */
+ ret = gst_pngdec_caps_create_and_set (pngdec);
+ if (ret != GST_FLOW_OK) {
+ goto beach;
+ }
+
+ /* Allocate output buffer */
+ pngdec->rowbytes = png_get_rowbytes (pngdec->png, pngdec->info);
+ if (pngdec->rowbytes > (G_MAXUINT32 - 3)
+ || pngdec->height > G_MAXUINT32 / pngdec->rowbytes) {
+ ret = GST_FLOW_ERROR;
+ goto beach;
+ }
+ pngdec->rowbytes = GST_ROUND_UP_4 (pngdec->rowbytes);
+ buffer_size = pngdec->height * pngdec->rowbytes;
+
+ ret =
+ gst_pad_alloc_buffer_and_set_caps (pngdec->srcpad, GST_BUFFER_OFFSET_NONE,
+ buffer_size, GST_PAD_CAPS (pngdec->srcpad), &buffer);
+ if (ret != GST_FLOW_OK) {
+ goto beach;
+ }
+
+ pngdec->buffer_out = buffer;
+
+beach:
+ pngdec->ret = ret;
+}
+
+static void
+user_endrow_callback (png_structp png_ptr, png_bytep new_row,
+ png_uint_32 row_num, int pass)
+{
+ GstPngDec *pngdec = NULL;
+
+ pngdec = GST_PNGDEC (png_get_io_ptr (png_ptr));
+
+ /* FIXME: implement interlaced pictures */
+
+ /* If buffer_out doesn't exist, it means buffer_alloc failed, which
+ * will already have set the return code */
+ if (GST_IS_BUFFER (pngdec->buffer_out)) {
+ size_t offset = row_num * pngdec->rowbytes;
+
+ GST_LOG ("got row %u, copying in buffer %p at offset %" G_GSIZE_FORMAT,
+ (guint) row_num, pngdec->buffer_out, offset);
+ memcpy (GST_BUFFER_DATA (pngdec->buffer_out) + offset, new_row,
+ pngdec->rowbytes);
+ pngdec->ret = GST_FLOW_OK;
+ }
+}
+
+static gboolean
+buffer_clip (GstPngDec * dec, GstBuffer * buffer)
+{
+ gboolean res = TRUE;
+ gint64 cstart, cstop;
+
+
+ if ((!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) ||
+ (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) ||
+ (dec->segment.format != GST_FORMAT_TIME))
+ goto beach;
+
+ cstart = GST_BUFFER_TIMESTAMP (buffer);
+ cstop = GST_BUFFER_DURATION (buffer);
+
+ if ((res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME,
+ cstart, cstart + cstop, &cstart, &cstop))) {
+ GST_BUFFER_TIMESTAMP (buffer) = cstart;
+ GST_BUFFER_DURATION (buffer) = cstop - cstart;
+ }
+
+beach:
+ return res;
+}
+
+static void
+user_end_callback (png_structp png_ptr, png_infop info)
+{
+ GstPngDec *pngdec = NULL;
+
+ pngdec = GST_PNGDEC (png_get_io_ptr (png_ptr));
+
+ GST_LOG_OBJECT (pngdec, "and we are done reading this image");
+
+ if (!pngdec->buffer_out)
+ return;
+
+ if (GST_CLOCK_TIME_IS_VALID (pngdec->in_timestamp))
+ GST_BUFFER_TIMESTAMP (pngdec->buffer_out) = pngdec->in_timestamp;
+ if (GST_CLOCK_TIME_IS_VALID (pngdec->in_duration))
+ GST_BUFFER_DURATION (pngdec->buffer_out) = pngdec->in_duration;
+
+ /* buffer clipping */
+ if (buffer_clip (pngdec, pngdec->buffer_out)) {
+ /* Push our buffer and then EOS if needed */
+ GST_LOG_OBJECT (pngdec, "pushing buffer with ts=%" GST_TIME_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (pngdec->buffer_out)));
+
+ pngdec->ret = gst_pad_push (pngdec->srcpad, pngdec->buffer_out);
+ } else {
+ GST_LOG_OBJECT (pngdec, "dropped decoded buffer");
+ gst_buffer_unref (pngdec->buffer_out);
+ }
+ pngdec->buffer_out = NULL;
+ pngdec->image_ready = TRUE;
+}
+
+static void
+user_read_data (png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ GstPngDec *pngdec;
+ GstBuffer *buffer;
+ GstFlowReturn ret = GST_FLOW_OK;
+ guint size;
+
+ pngdec = GST_PNGDEC (png_get_io_ptr (png_ptr));
+
+ GST_LOG ("reading %" G_GSIZE_FORMAT " bytes of data at offset %d", length,
+ pngdec->offset);
+
+ ret = gst_pad_pull_range (pngdec->sinkpad, pngdec->offset, length, &buffer);
+ if (ret != GST_FLOW_OK)
+ goto pause;
+
+ size = GST_BUFFER_SIZE (buffer);
+
+ if (size != length)
+ goto short_buffer;
+
+ memcpy (data, GST_BUFFER_DATA (buffer), size);
+
+ gst_buffer_unref (buffer);
+
+ pngdec->offset += length;
+
+ return;
+
+ /* ERRORS */
+pause:
+ {
+ GST_INFO_OBJECT (pngdec, "pausing task, reason %s",
+ gst_flow_get_name (ret));
+ gst_pad_pause_task (pngdec->sinkpad);
+ if (ret == GST_FLOW_UNEXPECTED) {
+ gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ());
+ } else if (ret < GST_FLOW_UNEXPECTED || ret == GST_FLOW_NOT_LINKED) {
+ GST_ELEMENT_ERROR (pngdec, STREAM, FAILED,
+ (_("Internal data stream error.")),
+ ("stream stopped, reason %s", gst_flow_get_name (ret)));
+ gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ());
+ }
+ png_error (png_ptr, "Internal data stream error.");
+ return;
+ }
+short_buffer:
+ {
+ gst_buffer_unref (buffer);
+ GST_ELEMENT_ERROR (pngdec, STREAM, FAILED,
+ (_("Internal data stream error.")),
+ ("Read %u, needed %" G_GSIZE_FORMAT "bytes", size, length));
+ ret = GST_FLOW_ERROR;
+ goto pause;
+ }
+}
+
+static GstFlowReturn
+gst_pngdec_caps_create_and_set (GstPngDec * pngdec)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstCaps *caps = NULL, *res = NULL;
+ GstPadTemplate *templ = NULL;
+ gint bpc = 0, color_type;
+ png_uint_32 width, height;
+
+ g_return_val_if_fail (GST_IS_PNGDEC (pngdec), GST_FLOW_ERROR);
+
+ /* Get bits per channel */
+ bpc = png_get_bit_depth (pngdec->png, pngdec->info);
+ if (bpc > 8) {
+ /* Add alpha channel if 16-bit depth */
+ png_set_add_alpha (pngdec->png, 0xffff, PNG_FILLER_BEFORE);
+ png_set_swap (pngdec->png);
+ }
+
+ /* Get Color type */
+ color_type = png_get_color_type (pngdec->png, pngdec->info);
+
+#if 0
+ /* We used to have this HACK to reverse the outgoing bytes, but the problem
+ * that originally required the hack seems to have been in ffmpegcolorspace's
+ * RGBA descriptions. It doesn't seem needed now that's fixed, but might
+ * still be needed on big-endian systems, I'm not sure. J.S. 6/7/2007 */
+ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_bgr (pngdec->png);
+#endif
+
+ /* Gray scale converted to RGB and upscaled to 8 bits */
+ if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
+ (color_type == PNG_COLOR_TYPE_GRAY)) {
+ GST_LOG_OBJECT (pngdec, "converting grayscale png to RGB");
+ png_set_gray_to_rgb (pngdec->png);
+ if (bpc < 8) { /* Convert to 8 bits */
+ GST_LOG_OBJECT (pngdec, "converting grayscale image to 8 bits");
+#if PNG_LIBPNG_VER < 10400
+ png_set_gray_1_2_4_to_8 (pngdec->png);
+#else
+ png_set_expand_gray_1_2_4_to_8 (pngdec->png);
+#endif
+ }
+ }
+
+ /* Palette converted to RGB */
+ if (color_type == PNG_COLOR_TYPE_PALETTE) {
+ GST_LOG_OBJECT (pngdec, "converting palette png to RGB");
+ png_set_palette_to_rgb (pngdec->png);
+ }
+
+ /* Update the info structure */
+ png_read_update_info (pngdec->png, pngdec->info);
+
+ /* Get IHDR header again after transformation settings */
+
+ png_get_IHDR (pngdec->png, pngdec->info, &width, &height,
+ &bpc, &pngdec->color_type, NULL, NULL, NULL);
+
+ pngdec->width = width;
+ pngdec->height = height;
+
+ GST_LOG_OBJECT (pngdec, "this is a %dx%d PNG image", pngdec->width,
+ pngdec->height);
+
+ switch (pngdec->color_type) {
+ case PNG_COLOR_TYPE_RGB:
+ GST_LOG_OBJECT (pngdec, "we have no alpha channel, depth is 24 bits");
+ pngdec->bpp = 3 * bpc;
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ GST_LOG_OBJECT (pngdec, "we have an alpha channel, depth is 32 bits");
+ pngdec->bpp = 4 * bpc;
+ break;
+ default:
+ GST_ELEMENT_ERROR (pngdec, STREAM, NOT_IMPLEMENTED, (NULL),
+ ("pngdec does not support this color type"));
+ ret = GST_FLOW_NOT_SUPPORTED;
+ goto beach;
+ }
+
+ caps = gst_caps_new_simple ("video/x-raw-rgb",
+ "width", G_TYPE_INT, pngdec->width,
+ "height", G_TYPE_INT, pngdec->height,
+ "bpp", G_TYPE_INT, pngdec->bpp,
+ "framerate", GST_TYPE_FRACTION, pngdec->fps_n, pngdec->fps_d, NULL);
+
+ templ = gst_static_pad_template_get (&gst_pngdec_src_pad_template);
+
+ res = gst_caps_intersect (caps, gst_pad_template_get_caps (templ));
+
+ gst_caps_unref (caps);
+ gst_object_unref (templ);
+
+ if (!gst_pad_set_caps (pngdec->srcpad, res))
+ ret = GST_FLOW_NOT_NEGOTIATED;
+
+ GST_DEBUG_OBJECT (pngdec, "our caps %" GST_PTR_FORMAT, res);
+
+ gst_caps_unref (res);
+
+ /* Push a newsegment event */
+ if (pngdec->need_newsegment) {
+ gst_pad_push_event (pngdec->srcpad,
+ gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0));
+ pngdec->need_newsegment = FALSE;
+ }
+
+beach:
+ return ret;
+}
+
+static void
+gst_pngdec_task (GstPad * pad)
+{
+ GstPngDec *pngdec;
+ GstBuffer *buffer = NULL;
+ size_t buffer_size = 0;
+ gint i = 0;
+ png_bytep *rows, inp;
+ png_uint_32 rowbytes;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ pngdec = GST_PNGDEC (GST_OBJECT_PARENT (pad));
+
+ GST_LOG_OBJECT (pngdec, "read frame");
+
+ /* Let libpng come back here on error */
+ if (setjmp (png_jmpbuf (pngdec->png))) {
+ ret = GST_FLOW_ERROR;
+ goto pause;
+ }
+
+ /* Set reading callback */
+ png_set_read_fn (pngdec->png, pngdec, user_read_data);
+
+ /* Read info */
+ png_read_info (pngdec->png, pngdec->info);
+
+ /* Generate the caps and configure */
+ ret = gst_pngdec_caps_create_and_set (pngdec);
+ if (ret != GST_FLOW_OK) {
+ goto pause;
+ }
+
+ /* Allocate output buffer */
+ rowbytes = png_get_rowbytes (pngdec->png, pngdec->info);
+ if (rowbytes > (G_MAXUINT32 - 3) || pngdec->height > G_MAXUINT32 / rowbytes) {
+ ret = GST_FLOW_ERROR;
+ goto pause;
+ }
+ rowbytes = GST_ROUND_UP_4 (rowbytes);
+ buffer_size = pngdec->height * rowbytes;
+ ret =
+ gst_pad_alloc_buffer_and_set_caps (pngdec->srcpad, GST_BUFFER_OFFSET_NONE,
+ buffer_size, GST_PAD_CAPS (pngdec->srcpad), &buffer);
+ if (ret != GST_FLOW_OK)
+ goto pause;
+
+ rows = (png_bytep *) g_malloc (sizeof (png_bytep) * pngdec->height);
+
+ inp = GST_BUFFER_DATA (buffer);
+
+ for (i = 0; i < pngdec->height; i++) {
+ rows[i] = inp;
+ inp += rowbytes;
+ }
+
+ /* Read the actual picture */
+ png_read_image (pngdec->png, rows);
+ g_free (rows);
+
+ /* Push the raw RGB frame */
+ ret = gst_pad_push (pngdec->srcpad, buffer);
+ if (ret != GST_FLOW_OK)
+ goto pause;
+
+ /* And we are done */
+ gst_pad_pause_task (pngdec->sinkpad);
+ gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ());
+ return;
+
+pause:
+ {
+ GST_INFO_OBJECT (pngdec, "pausing task, reason %s",
+ gst_flow_get_name (ret));
+ gst_pad_pause_task (pngdec->sinkpad);
+ if (ret == GST_FLOW_UNEXPECTED) {
+ gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ());
+ } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
+ GST_ELEMENT_ERROR (pngdec, STREAM, FAILED,
+ (_("Internal data stream error.")),
+ ("stream stopped, reason %s", gst_flow_get_name (ret)));
+ gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ());
+ }
+ }
+}
+
+static GstFlowReturn
+gst_pngdec_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstPngDec *pngdec;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ pngdec = GST_PNGDEC (gst_pad_get_parent (pad));
+
+ GST_LOG_OBJECT (pngdec, "Got buffer, size=%u", GST_BUFFER_SIZE (buffer));
+
+ if (G_UNLIKELY (!pngdec->setup))
+ goto not_configured;
+
+ /* Something is going wrong in our callbacks */
+ ret = pngdec->ret;
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ GST_WARNING_OBJECT (pngdec, "we have a pending return code of %d", ret);
+ goto beach;
+ }
+
+ /* Let libpng come back here on error */
+ if (setjmp (png_jmpbuf (pngdec->png))) {
+ GST_WARNING_OBJECT (pngdec, "error during decoding");
+ ret = GST_FLOW_ERROR;
+ goto beach;
+ }
+
+ pngdec->in_timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ pngdec->in_duration = GST_BUFFER_DURATION (buffer);
+
+ /* Progressive loading of the PNG image */
+ png_process_data (pngdec->png, pngdec->info, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer));
+
+ if (pngdec->image_ready) {
+ if (pngdec->framed) {
+ /* Reset ourselves for the next frame */
+ gst_pngdec_libpng_clear (pngdec);
+ gst_pngdec_libpng_init (pngdec);
+ GST_LOG_OBJECT (pngdec, "setting up callbacks for next frame");
+ png_set_progressive_read_fn (pngdec->png, pngdec,
+ user_info_callback, user_endrow_callback, user_end_callback);
+ } else {
+ GST_LOG_OBJECT (pngdec, "sending EOS");
+ pngdec->ret = gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ());
+ }
+ pngdec->image_ready = FALSE;
+ }
+
+ /* grab new return code */
+ ret = pngdec->ret;
+
+ /* And release the buffer */
+ gst_buffer_unref (buffer);
+
+beach:
+ gst_object_unref (pngdec);
+
+ return ret;
+
+ /* ERRORS */
+not_configured:
+ {
+ GST_LOG_OBJECT (pngdec, "we are not configured yet");
+ ret = GST_FLOW_WRONG_STATE;
+ goto beach;
+ }
+}
+
+static gboolean
+gst_pngdec_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstStructure *s;
+ GstPngDec *pngdec;
+ gint num, denom;
+
+ pngdec = GST_PNGDEC (gst_pad_get_parent (pad));
+
+ s = gst_caps_get_structure (caps, 0);
+ if (gst_structure_get_fraction (s, "framerate", &num, &denom)) {
+ GST_DEBUG_OBJECT (pngdec, "framed input");
+ pngdec->framed = TRUE;
+ pngdec->fps_n = num;
+ pngdec->fps_d = denom;
+ } else {
+ GST_DEBUG_OBJECT (pngdec, "single picture input");
+ pngdec->framed = FALSE;
+ pngdec->fps_n = 0;
+ pngdec->fps_d = 1;
+ }
+
+ gst_object_unref (pngdec);
+ return TRUE;
+}
+
+static gboolean
+gst_pngdec_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstPngDec *pngdec;
+ gboolean res;
+
+ pngdec = GST_PNGDEC (gst_pad_get_parent (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_NEWSEGMENT:{
+ gdouble rate, arate;
+ gboolean update;
+ gint64 start, stop, position;
+ GstFormat fmt;
+
+ gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
+ &start, &stop, &position);
+
+ gst_segment_set_newsegment_full (&pngdec->segment, update, rate, arate,
+ fmt, start, stop, position);
+
+ GST_LOG_OBJECT (pngdec, "NEWSEGMENT (%s)", gst_format_get_name (fmt));
+
+ if (fmt == GST_FORMAT_TIME) {
+ pngdec->need_newsegment = FALSE;
+ res = gst_pad_push_event (pngdec->srcpad, event);
+ } else {
+ gst_event_unref (event);
+ res = TRUE;
+ }
+ break;
+ }
+ case GST_EVENT_FLUSH_STOP:
+ {
+ gst_pngdec_libpng_clear (pngdec);
+ gst_pngdec_libpng_init (pngdec);
+ png_set_progressive_read_fn (pngdec->png, pngdec,
+ user_info_callback, user_endrow_callback, user_end_callback);
+ pngdec->ret = GST_FLOW_OK;
+ gst_segment_init (&pngdec->segment, GST_FORMAT_UNDEFINED);
+ res = gst_pad_push_event (pngdec->srcpad, event);
+ break;
+ }
+ case GST_EVENT_EOS:
+ {
+ GST_LOG_OBJECT (pngdec, "EOS");
+ gst_pngdec_libpng_clear (pngdec);
+ pngdec->ret = GST_FLOW_UNEXPECTED;
+ res = gst_pad_push_event (pngdec->srcpad, event);
+ break;
+ }
+ default:
+ res = gst_pad_push_event (pngdec->srcpad, event);
+ break;
+ }
+
+ gst_object_unref (pngdec);
+ return res;
+}
+
+
+/* Clean up the libpng structures */
+static gboolean
+gst_pngdec_libpng_clear (GstPngDec * pngdec)
+{
+ png_infopp info = NULL, endinfo = NULL;
+
+ g_return_val_if_fail (GST_IS_PNGDEC (pngdec), FALSE);
+
+ GST_LOG ("cleaning up libpng structures");
+
+ if (pngdec->info) {
+ info = &pngdec->info;
+ }
+
+ if (pngdec->endinfo) {
+ endinfo = &pngdec->endinfo;
+ }
+
+ if (pngdec->png) {
+ png_destroy_read_struct (&(pngdec->png), info, endinfo);
+ pngdec->png = NULL;
+ pngdec->info = NULL;
+ pngdec->endinfo = NULL;
+ }
+
+ pngdec->bpp = pngdec->color_type = pngdec->height = pngdec->width = -1;
+ pngdec->offset = 0;
+ pngdec->rowbytes = 0;
+ pngdec->buffer_out = NULL;
+
+ pngdec->setup = FALSE;
+
+ pngdec->in_timestamp = GST_CLOCK_TIME_NONE;
+ pngdec->in_duration = GST_CLOCK_TIME_NONE;
+
+ return TRUE;
+}
+
+static gboolean
+gst_pngdec_libpng_init (GstPngDec * pngdec)
+{
+ g_return_val_if_fail (GST_IS_PNGDEC (pngdec), FALSE);
+
+ if (pngdec->setup)
+ return TRUE;
+
+ GST_LOG ("init libpng structures");
+
+ /* initialize png struct stuff */
+ pngdec->png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
+ (png_voidp) NULL, user_error_fn, user_warning_fn);
+
+ if (pngdec->png == NULL)
+ goto init_failed;
+
+ pngdec->info = png_create_info_struct (pngdec->png);
+ if (pngdec->info == NULL)
+ goto info_failed;
+
+ pngdec->endinfo = png_create_info_struct (pngdec->png);
+ if (pngdec->endinfo == NULL)
+ goto endinfo_failed;
+
+ pngdec->setup = TRUE;
+
+ return TRUE;
+
+ /* ERRORS */
+init_failed:
+ {
+ GST_ELEMENT_ERROR (pngdec, LIBRARY, INIT, (NULL),
+ ("Failed to initialize png structure"));
+ return FALSE;
+ }
+info_failed:
+ {
+ gst_pngdec_libpng_clear (pngdec);
+ GST_ELEMENT_ERROR (pngdec, LIBRARY, INIT, (NULL),
+ ("Failed to initialize info structure"));
+ return FALSE;
+ }
+endinfo_failed:
+ {
+ gst_pngdec_libpng_clear (pngdec);
+ GST_ELEMENT_ERROR (pngdec, LIBRARY, INIT, (NULL),
+ ("Failed to initialize endinfo structure"));
+ return FALSE;
+ }
+}
+
+static GstStateChangeReturn
+gst_pngdec_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstPngDec *pngdec;
+
+ pngdec = GST_PNGDEC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_pngdec_libpng_init (pngdec);
+ pngdec->need_newsegment = TRUE;
+ pngdec->framed = FALSE;
+ pngdec->ret = GST_FLOW_OK;
+ gst_segment_init (&pngdec->segment, GST_FORMAT_UNDEFINED);
+ break;
+ default:
+ break;
+ }
+
+ ret = parent_class->change_state (element, transition);
+ if (ret != GST_STATE_CHANGE_SUCCESS)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_pngdec_libpng_clear (pngdec);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/* this function gets called when we activate ourselves in push mode. */
+static gboolean
+gst_pngdec_sink_activate_push (GstPad * sinkpad, gboolean active)
+{
+ GstPngDec *pngdec;
+
+ pngdec = GST_PNGDEC (GST_OBJECT_PARENT (sinkpad));
+
+ pngdec->ret = GST_FLOW_OK;
+
+ if (active) {
+ /* Let libpng come back here on error */
+ if (setjmp (png_jmpbuf (pngdec->png)))
+ goto setup_failed;
+
+ GST_LOG ("setting up progressive loading callbacks");
+ png_set_progressive_read_fn (pngdec->png, pngdec,
+ user_info_callback, user_endrow_callback, user_end_callback);
+ }
+ return TRUE;
+
+setup_failed:
+ {
+ GST_LOG ("failed setting up libpng jmpbuf");
+ gst_pngdec_libpng_clear (pngdec);
+ return FALSE;
+ }
+}
+
+/* this function gets called when we activate ourselves in pull mode.
+ * We can perform random access to the resource and we start a task
+ * to start reading */
+static gboolean
+gst_pngdec_sink_activate_pull (GstPad * sinkpad, gboolean active)
+{
+ if (active) {
+ return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_pngdec_task,
+ sinkpad);
+ } else {
+ return gst_pad_stop_task (sinkpad);
+ }
+}
+
+/* this function is called when the pad is activated and should start
+ * processing data.
+ *
+ * We check if we can do random access to decide if we work push or
+ * pull based.
+ */
+static gboolean
+gst_pngdec_sink_activate (GstPad * sinkpad)
+{
+ if (gst_pad_check_pull_range (sinkpad)) {
+ return gst_pad_activate_pull (sinkpad, TRUE);
+ } else {
+ return gst_pad_activate_push (sinkpad, TRUE);
+ }
+}
diff --git a/ext/libpng/gstpngdec.h b/ext/libpng/gstpngdec.h
new file mode 100644
index 0000000..439b293
--- /dev/null
+++ b/ext/libpng/gstpngdec.h
@@ -0,0 +1,84 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_PNGDEC_H__
+#define __GST_PNGDEC_H__
+
+#include <gst/gst.h>
+#include <png.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PNGDEC (gst_pngdec_get_type())
+#define GST_PNGDEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PNGDEC,GstPngDec))
+#define GST_PNGDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PNGDEC,GstPngDecClass))
+#define GST_IS_PNGDEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PNGDEC))
+#define GST_IS_PNGDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PNGDEC))
+
+typedef struct _GstPngDec GstPngDec;
+typedef struct _GstPngDecClass GstPngDecClass;
+
+struct _GstPngDec
+{
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+
+ gboolean need_newsegment;
+
+ /* Progressive */
+ GstBuffer *buffer_out;
+ GstFlowReturn ret;
+ png_uint_32 rowbytes;
+
+ /* Pull range */
+ gint offset;
+
+ png_structp png;
+ png_infop info;
+ png_infop endinfo;
+ gboolean setup;
+
+ gint width;
+ gint height;
+ gint bpp;
+ gint color_type;
+ gint fps_n;
+ gint fps_d;
+
+ /* Chain */
+ gboolean framed;
+ GstClockTime in_timestamp;
+ GstClockTime in_duration;
+
+ GstSegment segment;
+ gboolean image_ready;
+};
+
+struct _GstPngDecClass
+{
+ GstElementClass parent_class;
+};
+
+GType gst_pngdec_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_PNGDEC_H__ */
diff --git a/ext/libpng/gstpngenc.c b/ext/libpng/gstpngenc.c
new file mode 100644
index 0000000..30986cd
--- /dev/null
+++ b/ext/libpng/gstpngenc.c
@@ -0,0 +1,432 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * Filter:
+ * Copyright (C) 2000 Donald A. Graft
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+/**
+ * SECTION:element-pngenc
+ *
+ * Encodes png images.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+#include <gst/gst.h>
+#include "gstpngenc.h"
+#include <gst/video/video.h>
+#include <zlib.h>
+
+GST_DEBUG_CATEGORY_STATIC (pngenc_debug);
+#define GST_CAT_DEFAULT pngenc_debug
+
+/* Filter signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+#define DEFAULT_SNAPSHOT TRUE
+/* #define DEFAULT_NEWMEDIA FALSE */
+#define DEFAULT_COMPRESSION_LEVEL 6
+
+enum
+{
+ ARG_0,
+ ARG_SNAPSHOT,
+/* ARG_NEWMEDIA, */
+ ARG_COMPRESSION_LEVEL
+};
+
+static GstStaticPadTemplate pngenc_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("image/png, "
+ "width = (int) [ 16, 1000000 ], "
+ "height = (int) [ 16, 1000000 ], " "framerate = " GST_VIDEO_FPS_RANGE)
+ );
+
+static GstStaticPadTemplate pngenc_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_RGB ";"
+ GST_VIDEO_CAPS_GRAY8)
+ );
+
+/* static GstElementClass *parent_class = NULL; */
+
+GST_BOILERPLATE (GstPngEnc, gst_pngenc, GstElement, GST_TYPE_ELEMENT);
+
+static void gst_pngenc_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_pngenc_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_pngenc_chain (GstPad * pad, GstBuffer * data);
+
+static void
+user_error_fn (png_structp png_ptr, png_const_charp error_msg)
+{
+ g_warning ("%s", error_msg);
+}
+
+static void
+user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
+{
+ g_warning ("%s", warning_msg);
+}
+
+static void
+gst_pngenc_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template
+ (element_class, &pngenc_sink_template);
+ gst_element_class_add_static_pad_template
+ (element_class, &pngenc_src_template);
+ gst_element_class_set_details_simple (element_class, "PNG image encoder",
+ "Codec/Encoder/Image",
+ "Encode a video frame to a .png image",
+ "Jeremy SIMON <jsimon13@yahoo.fr>");
+}
+
+static void
+gst_pngenc_class_init (GstPngEncClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->get_property = gst_pngenc_get_property;
+ gobject_class->set_property = gst_pngenc_set_property;
+
+ g_object_class_install_property (gobject_class, ARG_SNAPSHOT,
+ g_param_spec_boolean ("snapshot", "Snapshot",
+ "Send EOS after encoding a frame, useful for snapshots",
+ DEFAULT_SNAPSHOT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+/* g_object_class_install_property (gobject_class, ARG_NEWMEDIA, */
+/* g_param_spec_boolean ("newmedia", "newmedia", */
+/* "Send new media discontinuity after encoding each frame", */
+/* DEFAULT_NEWMEDIA, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); */
+
+ g_object_class_install_property (gobject_class, ARG_COMPRESSION_LEVEL,
+ g_param_spec_uint ("compression-level", "compression-level",
+ "PNG compression level",
+ Z_NO_COMPRESSION, Z_BEST_COMPRESSION,
+ DEFAULT_COMPRESSION_LEVEL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ GST_DEBUG_CATEGORY_INIT (pngenc_debug, "pngenc", 0, "PNG image encoder");
+}
+
+
+static gboolean
+gst_pngenc_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstPngEnc *pngenc;
+ GstVideoFormat format;
+ int fps_n, fps_d;
+ GstCaps *pcaps;
+ gboolean ret;
+
+ pngenc = GST_PNGENC (gst_pad_get_parent (pad));
+
+ ret = gst_video_format_parse_caps (caps, &format,
+ &pngenc->width, &pngenc->height);
+ if (G_LIKELY (ret))
+ ret = gst_video_parse_caps_framerate (caps, &fps_n, &fps_d);
+
+ if (G_UNLIKELY (!ret))
+ goto done;
+
+ switch (format) {
+ case GST_VIDEO_FORMAT_RGBA:
+ pngenc->png_color_type = PNG_COLOR_TYPE_RGBA;
+ break;
+ case GST_VIDEO_FORMAT_RGB:
+ pngenc->png_color_type = PNG_COLOR_TYPE_RGB;
+ break;
+ case GST_VIDEO_FORMAT_GRAY8:
+ pngenc->png_color_type = PNG_COLOR_TYPE_GRAY;
+ break;
+ default:
+ ret = FALSE;
+ goto done;
+ }
+
+ if (G_UNLIKELY (pngenc->width < 16 || pngenc->width > 1000000 ||
+ pngenc->height < 16 || pngenc->height > 1000000)) {
+ ret = FALSE;
+ goto done;
+ }
+
+ pngenc->stride = gst_video_format_get_row_stride (format, 0, pngenc->width);
+
+ pcaps = gst_caps_new_simple ("image/png",
+ "width", G_TYPE_INT, pngenc->width,
+ "height", G_TYPE_INT, pngenc->height,
+ "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
+
+ ret = gst_pad_set_caps (pngenc->srcpad, pcaps);
+
+ gst_caps_unref (pcaps);
+
+ /* Fall-through. */
+done:
+ if (G_UNLIKELY (!ret)) {
+ pngenc->width = 0;
+ pngenc->height = 0;
+ }
+
+ gst_object_unref (pngenc);
+
+ return ret;
+}
+
+static void
+gst_pngenc_init (GstPngEnc * pngenc, GstPngEncClass * g_class)
+{
+ /* sinkpad */
+ pngenc->sinkpad = gst_pad_new_from_static_template
+ (&pngenc_sink_template, "sink");
+ gst_pad_set_chain_function (pngenc->sinkpad, gst_pngenc_chain);
+ /* gst_pad_set_link_function (pngenc->sinkpad, gst_pngenc_sinklink); */
+ /* gst_pad_set_getcaps_function (pngenc->sinkpad, gst_pngenc_sink_getcaps); */
+ gst_pad_set_setcaps_function (pngenc->sinkpad, gst_pngenc_setcaps);
+ gst_element_add_pad (GST_ELEMENT (pngenc), pngenc->sinkpad);
+
+ /* srcpad */
+ pngenc->srcpad = gst_pad_new_from_static_template
+ (&pngenc_src_template, "src");
+ /* pngenc->srcpad = gst_pad_new ("src", GST_PAD_SRC); */
+ /* gst_pad_set_getcaps_function (pngenc->srcpad, gst_pngenc_src_getcaps); */
+ /* gst_pad_set_setcaps_function (pngenc->srcpad, gst_pngenc_setcaps); */
+ gst_element_add_pad (GST_ELEMENT (pngenc), pngenc->srcpad);
+
+ /* init settings */
+ pngenc->png_struct_ptr = NULL;
+ pngenc->png_info_ptr = NULL;
+
+ pngenc->snapshot = DEFAULT_SNAPSHOT;
+/* pngenc->newmedia = FALSE; */
+ pngenc->compression_level = DEFAULT_COMPRESSION_LEVEL;
+}
+
+static void
+user_flush_data (png_structp png_ptr G_GNUC_UNUSED)
+{
+}
+
+static void
+user_write_data (png_structp png_ptr, png_bytep data, png_uint_32 length)
+{
+ GstPngEnc *pngenc;
+
+ pngenc = (GstPngEnc *) png_get_io_ptr (png_ptr);
+
+ if (pngenc->written + length >= GST_BUFFER_SIZE (pngenc->buffer_out)) {
+ GST_ERROR_OBJECT (pngenc, "output buffer bigger than the input buffer!?");
+ png_error (png_ptr, "output buffer bigger than the input buffer!?");
+
+ /* never reached */
+ return;
+ }
+
+ memcpy (GST_BUFFER_DATA (pngenc->buffer_out) + pngenc->written, data, length);
+ pngenc->written += length;
+}
+
+static GstFlowReturn
+gst_pngenc_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstPngEnc *pngenc;
+ gint row_index;
+ png_byte **row_pointers;
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstBuffer *encoded_buf = NULL;
+
+ pngenc = GST_PNGENC (gst_pad_get_parent (pad));
+
+ GST_DEBUG_OBJECT (pngenc, "BEGINNING");
+
+ if (G_UNLIKELY (pngenc->width <= 0 || pngenc->height <= 0)) {
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ goto done;
+ }
+
+ if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < pngenc->height * pngenc->stride)) {
+ gst_buffer_unref (buf);
+ GST_ELEMENT_ERROR (pngenc, STREAM, FORMAT, (NULL),
+ ("Provided input buffer is too small, caps problem?"));
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+
+ /* initialize png struct stuff */
+ pngenc->png_struct_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
+ (png_voidp) NULL, user_error_fn, user_warning_fn);
+ if (pngenc->png_struct_ptr == NULL) {
+ gst_buffer_unref (buf);
+ GST_ELEMENT_ERROR (pngenc, LIBRARY, INIT, (NULL),
+ ("Failed to initialize png structure"));
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+
+ pngenc->png_info_ptr = png_create_info_struct (pngenc->png_struct_ptr);
+ if (!pngenc->png_info_ptr) {
+ gst_buffer_unref (buf);
+ png_destroy_write_struct (&(pngenc->png_struct_ptr), (png_infopp) NULL);
+ GST_ELEMENT_ERROR (pngenc, LIBRARY, INIT, (NULL),
+ ("Failed to initialize the png info structure"));
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+
+ /* non-0 return is from a longjmp inside of libpng */
+ if (setjmp (png_jmpbuf (pngenc->png_struct_ptr)) != 0) {
+ gst_buffer_unref (buf);
+ png_destroy_write_struct (&pngenc->png_struct_ptr, &pngenc->png_info_ptr);
+ GST_ELEMENT_ERROR (pngenc, LIBRARY, FAILED, (NULL),
+ ("returning from longjmp"));
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+
+ png_set_filter (pngenc->png_struct_ptr, 0,
+ PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE);
+ png_set_compression_level (pngenc->png_struct_ptr, pngenc->compression_level);
+
+ png_set_IHDR (pngenc->png_struct_ptr,
+ pngenc->png_info_ptr,
+ pngenc->width,
+ pngenc->height,
+ 8,
+ pngenc->png_color_type,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ png_set_write_fn (pngenc->png_struct_ptr, pngenc,
+ (png_rw_ptr) user_write_data, user_flush_data);
+
+ row_pointers = g_new (png_byte *, pngenc->height);
+
+ for (row_index = 0; row_index < pngenc->height; row_index++) {
+ row_pointers[row_index] = GST_BUFFER_DATA (buf) +
+ (row_index * pngenc->stride);
+ }
+
+ /* allocate the output buffer */
+ pngenc->buffer_out =
+ gst_buffer_new_and_alloc (pngenc->height * pngenc->stride);
+ pngenc->written = 0;
+
+ png_write_info (pngenc->png_struct_ptr, pngenc->png_info_ptr);
+ png_write_image (pngenc->png_struct_ptr, row_pointers);
+ png_write_end (pngenc->png_struct_ptr, NULL);
+
+ g_free (row_pointers);
+
+ encoded_buf = gst_buffer_create_sub (pngenc->buffer_out, 0, pngenc->written);
+
+ png_destroy_info_struct (pngenc->png_struct_ptr, &pngenc->png_info_ptr);
+ png_destroy_write_struct (&pngenc->png_struct_ptr, (png_infopp) NULL);
+ gst_buffer_copy_metadata (encoded_buf, buf, GST_BUFFER_COPY_TIMESTAMPS);
+ gst_buffer_unref (buf);
+ gst_buffer_set_caps (encoded_buf, GST_PAD_CAPS (pngenc->srcpad));
+
+ if ((ret = gst_pad_push (pngenc->srcpad, encoded_buf)) != GST_FLOW_OK)
+ goto done;
+
+ if (pngenc->snapshot) {
+ GstEvent *event;
+
+ GST_DEBUG_OBJECT (pngenc, "snapshot mode, sending EOS");
+ /* send EOS event, since a frame has been pushed out */
+ event = gst_event_new_eos ();
+
+ gst_pad_push_event (pngenc->srcpad, event);
+ ret = GST_FLOW_UNEXPECTED;
+ }
+
+done:
+ GST_DEBUG_OBJECT (pngenc, "END, ret:%d", ret);
+
+ if (pngenc->buffer_out != NULL) {
+ gst_buffer_unref (pngenc->buffer_out);
+ pngenc->buffer_out = NULL;
+ }
+
+ gst_object_unref (pngenc);
+ return ret;
+}
+
+
+static void
+gst_pngenc_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstPngEnc *pngenc;
+
+ pngenc = GST_PNGENC (object);
+
+ switch (prop_id) {
+ case ARG_SNAPSHOT:
+ g_value_set_boolean (value, pngenc->snapshot);
+ break;
+/* case ARG_NEWMEDIA: */
+/* g_value_set_boolean (value, pngenc->newmedia); */
+/* break; */
+ case ARG_COMPRESSION_LEVEL:
+ g_value_set_uint (value, pngenc->compression_level);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+static void
+gst_pngenc_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstPngEnc *pngenc;
+
+ pngenc = GST_PNGENC (object);
+
+ switch (prop_id) {
+ case ARG_SNAPSHOT:
+ pngenc->snapshot = g_value_get_boolean (value);
+ break;
+/* case ARG_NEWMEDIA: */
+/* pngenc->newmedia = g_value_get_boolean (value); */
+/* break; */
+ case ARG_COMPRESSION_LEVEL:
+ pngenc->compression_level = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
diff --git a/ext/libpng/gstpngenc.h b/ext/libpng/gstpngenc.h
new file mode 100644
index 0000000..792a7c9
--- /dev/null
+++ b/ext/libpng/gstpngenc.h
@@ -0,0 +1,75 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_PNGENC_H__
+#define __GST_PNGENC_H__
+
+#include <gst/gst.h>
+#include <png.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_PNGENC (gst_pngenc_get_type())
+#define GST_PNGENC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PNGENC,GstPngEnc))
+#define GST_PNGENC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PNGENC,GstPngEncClass))
+#define GST_IS_PNGENC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PNGENC))
+#define GST_IS_PNGENC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PNGENC))
+
+typedef struct _GstPngEnc GstPngEnc;
+typedef struct _GstPngEncClass GstPngEncClass;
+
+struct _GstPngEnc
+{
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+ GstBuffer *buffer_out;
+ guint written;
+
+ png_structp png_struct_ptr;
+ png_infop png_info_ptr;
+
+ gint png_color_type;
+ gint width;
+ gint height;
+ gint stride;
+ guint compression_level;
+
+ gboolean snapshot;
+ gboolean newmedia;
+};
+
+struct _GstPngEncClass
+{
+ GstElementClass parent_class;
+};
+
+GType gst_pngenc_get_type(void);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_PNGENC_H__ */
diff --git a/ext/pulse/Makefile.am b/ext/pulse/Makefile.am
new file mode 100644
index 0000000..2438f5e
--- /dev/null
+++ b/ext/pulse/Makefile.am
@@ -0,0 +1,29 @@
+plugin_LTLIBRARIES = libgstpulse.la
+
+libgstpulse_la_SOURCES = \
+ plugin.c \
+ pulsemixer.c \
+ pulsemixerctrl.c \
+ pulsemixertrack.c \
+ pulseprobe.c \
+ pulsesink.c \
+ pulseaudiosink.c \
+ pulsesrc.c \
+ pulseutil.c
+
+libgstpulse_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(PULSE_CFLAGS)
+libgstpulse_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
+ -lgstinterfaces-$(GST_MAJORMINOR) -lgstpbutils-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) $(GST_LIBS) $(PULSE_LIBS)
+libgstpulse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstpulse_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = \
+ pulsemixerctrl.h \
+ pulsemixer.h \
+ pulsemixertrack.h \
+ pulseprobe.h \
+ pulsesink.h \
+ pulsesrc.h \
+ pulseutil.h
+
diff --git a/ext/pulse/Makefile.in b/ext/pulse/Makefile.in
new file mode 100644
index 0000000..5bdbb98
--- /dev/null
+++ b/ext/pulse/Makefile.in
@@ -0,0 +1,895 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/pulse
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstpulse_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgstpulse_la_OBJECTS = libgstpulse_la-plugin.lo \
+ libgstpulse_la-pulsemixer.lo libgstpulse_la-pulsemixerctrl.lo \
+ libgstpulse_la-pulsemixertrack.lo libgstpulse_la-pulseprobe.lo \
+ libgstpulse_la-pulsesink.lo libgstpulse_la-pulseaudiosink.lo \
+ libgstpulse_la-pulsesrc.lo libgstpulse_la-pulseutil.lo
+libgstpulse_la_OBJECTS = $(am_libgstpulse_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstpulse_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstpulse_la_CFLAGS) $(CFLAGS) \
+ $(libgstpulse_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstpulse_la_SOURCES)
+DIST_SOURCES = $(libgstpulse_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstpulse.la
+libgstpulse_la_SOURCES = \
+ plugin.c \
+ pulsemixer.c \
+ pulsemixerctrl.c \
+ pulsemixertrack.c \
+ pulseprobe.c \
+ pulsesink.c \
+ pulseaudiosink.c \
+ pulsesrc.c \
+ pulseutil.c
+
+libgstpulse_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(PULSE_CFLAGS)
+libgstpulse_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
+ -lgstinterfaces-$(GST_MAJORMINOR) -lgstpbutils-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) $(GST_LIBS) $(PULSE_LIBS)
+
+libgstpulse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstpulse_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = \
+ pulsemixerctrl.h \
+ pulsemixer.h \
+ pulsemixertrack.h \
+ pulseprobe.h \
+ pulsesink.h \
+ pulsesrc.h \
+ pulseutil.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/pulse/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/pulse/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstpulse.la: $(libgstpulse_la_OBJECTS) $(libgstpulse_la_DEPENDENCIES) $(EXTRA_libgstpulse_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstpulse_la_LINK) -rpath $(plugindir) $(libgstpulse_la_OBJECTS) $(libgstpulse_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstpulse_la-plugin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstpulse_la-pulseaudiosink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstpulse_la-pulsemixer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstpulse_la-pulsemixerctrl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstpulse_la-pulsemixertrack.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstpulse_la-pulseprobe.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstpulse_la-pulsesink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstpulse_la-pulsesrc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstpulse_la-pulseutil.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstpulse_la-plugin.lo: plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -MT libgstpulse_la-plugin.lo -MD -MP -MF $(DEPDIR)/libgstpulse_la-plugin.Tpo -c -o libgstpulse_la-plugin.lo `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstpulse_la-plugin.Tpo $(DEPDIR)/libgstpulse_la-plugin.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugin.c' object='libgstpulse_la-plugin.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -c -o libgstpulse_la-plugin.lo `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
+
+libgstpulse_la-pulsemixer.lo: pulsemixer.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -MT libgstpulse_la-pulsemixer.lo -MD -MP -MF $(DEPDIR)/libgstpulse_la-pulsemixer.Tpo -c -o libgstpulse_la-pulsemixer.lo `test -f 'pulsemixer.c' || echo '$(srcdir)/'`pulsemixer.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstpulse_la-pulsemixer.Tpo $(DEPDIR)/libgstpulse_la-pulsemixer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pulsemixer.c' object='libgstpulse_la-pulsemixer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -c -o libgstpulse_la-pulsemixer.lo `test -f 'pulsemixer.c' || echo '$(srcdir)/'`pulsemixer.c
+
+libgstpulse_la-pulsemixerctrl.lo: pulsemixerctrl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -MT libgstpulse_la-pulsemixerctrl.lo -MD -MP -MF $(DEPDIR)/libgstpulse_la-pulsemixerctrl.Tpo -c -o libgstpulse_la-pulsemixerctrl.lo `test -f 'pulsemixerctrl.c' || echo '$(srcdir)/'`pulsemixerctrl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstpulse_la-pulsemixerctrl.Tpo $(DEPDIR)/libgstpulse_la-pulsemixerctrl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pulsemixerctrl.c' object='libgstpulse_la-pulsemixerctrl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -c -o libgstpulse_la-pulsemixerctrl.lo `test -f 'pulsemixerctrl.c' || echo '$(srcdir)/'`pulsemixerctrl.c
+
+libgstpulse_la-pulsemixertrack.lo: pulsemixertrack.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -MT libgstpulse_la-pulsemixertrack.lo -MD -MP -MF $(DEPDIR)/libgstpulse_la-pulsemixertrack.Tpo -c -o libgstpulse_la-pulsemixertrack.lo `test -f 'pulsemixertrack.c' || echo '$(srcdir)/'`pulsemixertrack.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstpulse_la-pulsemixertrack.Tpo $(DEPDIR)/libgstpulse_la-pulsemixertrack.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pulsemixertrack.c' object='libgstpulse_la-pulsemixertrack.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -c -o libgstpulse_la-pulsemixertrack.lo `test -f 'pulsemixertrack.c' || echo '$(srcdir)/'`pulsemixertrack.c
+
+libgstpulse_la-pulseprobe.lo: pulseprobe.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -MT libgstpulse_la-pulseprobe.lo -MD -MP -MF $(DEPDIR)/libgstpulse_la-pulseprobe.Tpo -c -o libgstpulse_la-pulseprobe.lo `test -f 'pulseprobe.c' || echo '$(srcdir)/'`pulseprobe.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstpulse_la-pulseprobe.Tpo $(DEPDIR)/libgstpulse_la-pulseprobe.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pulseprobe.c' object='libgstpulse_la-pulseprobe.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -c -o libgstpulse_la-pulseprobe.lo `test -f 'pulseprobe.c' || echo '$(srcdir)/'`pulseprobe.c
+
+libgstpulse_la-pulsesink.lo: pulsesink.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -MT libgstpulse_la-pulsesink.lo -MD -MP -MF $(DEPDIR)/libgstpulse_la-pulsesink.Tpo -c -o libgstpulse_la-pulsesink.lo `test -f 'pulsesink.c' || echo '$(srcdir)/'`pulsesink.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstpulse_la-pulsesink.Tpo $(DEPDIR)/libgstpulse_la-pulsesink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pulsesink.c' object='libgstpulse_la-pulsesink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -c -o libgstpulse_la-pulsesink.lo `test -f 'pulsesink.c' || echo '$(srcdir)/'`pulsesink.c
+
+libgstpulse_la-pulseaudiosink.lo: pulseaudiosink.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -MT libgstpulse_la-pulseaudiosink.lo -MD -MP -MF $(DEPDIR)/libgstpulse_la-pulseaudiosink.Tpo -c -o libgstpulse_la-pulseaudiosink.lo `test -f 'pulseaudiosink.c' || echo '$(srcdir)/'`pulseaudiosink.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstpulse_la-pulseaudiosink.Tpo $(DEPDIR)/libgstpulse_la-pulseaudiosink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pulseaudiosink.c' object='libgstpulse_la-pulseaudiosink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -c -o libgstpulse_la-pulseaudiosink.lo `test -f 'pulseaudiosink.c' || echo '$(srcdir)/'`pulseaudiosink.c
+
+libgstpulse_la-pulsesrc.lo: pulsesrc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -MT libgstpulse_la-pulsesrc.lo -MD -MP -MF $(DEPDIR)/libgstpulse_la-pulsesrc.Tpo -c -o libgstpulse_la-pulsesrc.lo `test -f 'pulsesrc.c' || echo '$(srcdir)/'`pulsesrc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstpulse_la-pulsesrc.Tpo $(DEPDIR)/libgstpulse_la-pulsesrc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pulsesrc.c' object='libgstpulse_la-pulsesrc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -c -o libgstpulse_la-pulsesrc.lo `test -f 'pulsesrc.c' || echo '$(srcdir)/'`pulsesrc.c
+
+libgstpulse_la-pulseutil.lo: pulseutil.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -MT libgstpulse_la-pulseutil.lo -MD -MP -MF $(DEPDIR)/libgstpulse_la-pulseutil.Tpo -c -o libgstpulse_la-pulseutil.lo `test -f 'pulseutil.c' || echo '$(srcdir)/'`pulseutil.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstpulse_la-pulseutil.Tpo $(DEPDIR)/libgstpulse_la-pulseutil.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pulseutil.c' object='libgstpulse_la-pulseutil.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstpulse_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstpulse_la_CFLAGS) $(CFLAGS) -c -o libgstpulse_la-pulseutil.lo `test -f 'pulseutil.c' || echo '$(srcdir)/'`pulseutil.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/pulse/plugin.c b/ext/pulse/plugin.c
new file mode 100644
index 0000000..04c014f
--- /dev/null
+++ b/ext/pulse/plugin.c
@@ -0,0 +1,70 @@
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst-i18n-plugin.h>
+
+#include "pulsesink.h"
+#include "pulsesrc.h"
+#include "pulsemixer.h"
+
+GST_DEBUG_CATEGORY (pulse_debug);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+#ifdef ENABLE_NLS
+ GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+ LOCALEDIR);
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+ if (!gst_element_register (plugin, "pulsesink", GST_RANK_PRIMARY + 10,
+ GST_TYPE_PULSESINK))
+ return FALSE;
+
+ if (!gst_element_register (plugin, "pulsesrc", GST_RANK_PRIMARY + 10,
+ GST_TYPE_PULSESRC))
+ return FALSE;
+
+#ifdef HAVE_PULSE_1_0
+ if (!gst_element_register (plugin, "pulseaudiosink", GST_RANK_MARGINAL - 1,
+ GST_TYPE_PULSE_AUDIO_SINK))
+ return FALSE;
+#endif
+
+ if (!gst_element_register (plugin, "pulsemixer", GST_RANK_NONE,
+ GST_TYPE_PULSEMIXER))
+ return FALSE;
+
+ GST_DEBUG_CATEGORY_INIT (pulse_debug, "pulse", 0, "PulseAudio elements");
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "pulseaudio",
+ "PulseAudio plugin library",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/pulse/pulseaudiosink.c b/ext/pulse/pulseaudiosink.c
new file mode 100644
index 0000000..cd9f7d9
--- /dev/null
+++ b/ext/pulse/pulseaudiosink.c
@@ -0,0 +1,938 @@
+/*-*- Mode: C; c-basic-offset: 2 -*-*/
+
+/* GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2011 Intel Corporation
+ * 2011 Collabora
+ * 2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
+ * 2011 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+/**
+ * SECTION:element-pulseaudiosink
+ * @see_also: pulsesink, pulsesrc, pulsemixer
+ *
+ * This element outputs audio to a
+ * <ulink href="http://www.pulseaudio.org">PulseAudio sound server</ulink> via
+ * the @pulsesink element. It transparently takes care of passing compressed
+ * format as-is if the sink supports it, decoding if necessary, and changes
+ * to supported formats at runtime.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! pulseaudiosink
+ * ]| Decode and play an Ogg/Vorbis file.
+ * |[
+ * gst-launch -v filesrc location=test.mp3 ! mp3parse ! pulseaudiosink stream-properties="props,media.title=test"
+ * ]| Play an MP3 file on a sink that supports decoding directly, plug in a
+ * decoder if/when required.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_PULSE_1_0
+
+#include <gst/pbutils/pbutils.h>
+#include <gst/gst-i18n-plugin.h>
+#include <gst/glib-compat-private.h>
+
+#include <gst/audio/gstaudioiec61937.h>
+#include "pulsesink.h"
+
+GST_DEBUG_CATEGORY (pulseaudiosink_debug);
+#define GST_CAT_DEFAULT (pulseaudiosink_debug)
+
+#define GST_PULSE_AUDIO_SINK_LOCK(obj) G_STMT_START { \
+ GST_LOG_OBJECT (obj, \
+ "locking from thread %p", \
+ g_thread_self ()); \
+ g_mutex_lock (GST_PULSE_AUDIO_SINK_CAST(obj)->lock); \
+ GST_LOG_OBJECT (obj, \
+ "locked from thread %p", \
+ g_thread_self ()); \
+} G_STMT_END
+
+#define GST_PULSE_AUDIO_SINK_UNLOCK(obj) G_STMT_START { \
+ GST_LOG_OBJECT (obj, \
+ "unlocking from thread %p", \
+ g_thread_self ()); \
+ g_mutex_unlock (GST_PULSE_AUDIO_SINK_CAST(obj)->lock); \
+} G_STMT_END
+
+typedef struct
+{
+ GstBin parent;
+ GMutex *lock;
+
+ GstPad *sinkpad;
+ GstPad *sink_proxypad;
+ GstPadEventFunction sinkpad_old_eventfunc;
+ GstPadEventFunction proxypad_old_eventfunc;
+
+ GstPulseSink *psink;
+ GstElement *dbin2;
+
+ GstSegment segment;
+
+ guint event_probe_id;
+ gulong pad_added_id;
+
+ gboolean format_lost;
+} GstPulseAudioSink;
+
+typedef struct
+{
+ GstBinClass parent_class;
+ guint n_prop_own;
+ guint n_prop_total;
+} GstPulseAudioSinkClass;
+
+static void gst_pulse_audio_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_pulse_audio_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_pulse_audio_sink_dispose (GObject * object);
+static gboolean gst_pulse_audio_sink_src_event (GstPad * pad, GstEvent * event);
+static gboolean gst_pulse_audio_sink_sink_event (GstPad * pad,
+ GstEvent * event);
+static gboolean gst_pulse_audio_sink_sink_acceptcaps (GstPad * pad,
+ GstCaps * caps);
+static gboolean gst_pulse_audio_sink_sink_setcaps (GstPad * pad,
+ GstCaps * caps);
+static GstStateChangeReturn
+gst_pulse_audio_sink_change_state (GstElement * element,
+ GstStateChange transition);
+
+static void
+gst_pulse_audio_sink_do_init (GType type)
+{
+ GST_DEBUG_CATEGORY_INIT (pulseaudiosink_debug, "pulseaudiosink", 0,
+ "Bin that wraps pulsesink for handling compressed formats");
+}
+
+GST_BOILERPLATE_FULL (GstPulseAudioSink, gst_pulse_audio_sink, GstBin,
+ GST_TYPE_BIN, gst_pulse_audio_sink_do_init);
+
+static GstStaticPadTemplate sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (PULSE_SINK_TEMPLATE_CAPS));
+
+static void
+gst_pulse_audio_sink_base_init (gpointer klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_static_pad_template (element_class, &sink_template);
+
+ gst_element_class_set_details_simple (element_class,
+ "Bin wrapping pulsesink", "Sink/Audio/Bin",
+ "Correctly handles sink changes when streaming compressed formats to "
+ "pulsesink", "Arun Raghavan <arun.raghavan@collabora.co.uk>");
+}
+
+static GParamSpec *
+param_spec_copy (GParamSpec * spec)
+{
+ const char *name, *nick, *blurb;
+ GParamFlags flags;
+
+ name = g_param_spec_get_name (spec);
+ nick = g_param_spec_get_nick (spec);
+ blurb = g_param_spec_get_blurb (spec);
+ flags = spec->flags;
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_BOOLEAN) {
+ return g_param_spec_boolean (name, nick, blurb,
+ G_PARAM_SPEC_BOOLEAN (spec)->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_BOXED) {
+ return g_param_spec_boxed (name, nick, blurb, spec->value_type, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_CHAR) {
+ GParamSpecChar *cspec = G_PARAM_SPEC_CHAR (spec);
+ return g_param_spec_char (name, nick, blurb, cspec->minimum,
+ cspec->maximum, cspec->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_DOUBLE) {
+ GParamSpecDouble *dspec = G_PARAM_SPEC_DOUBLE (spec);
+ return g_param_spec_double (name, nick, blurb, dspec->minimum,
+ dspec->maximum, dspec->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_ENUM) {
+ return g_param_spec_enum (name, nick, blurb, spec->value_type,
+ G_PARAM_SPEC_ENUM (spec)->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_FLAGS) {
+ return g_param_spec_flags (name, nick, blurb, spec->value_type,
+ G_PARAM_SPEC_ENUM (spec)->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_FLOAT) {
+ GParamSpecFloat *fspec = G_PARAM_SPEC_FLOAT (spec);
+ return g_param_spec_double (name, nick, blurb, fspec->minimum,
+ fspec->maximum, fspec->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_GTYPE) {
+ return g_param_spec_gtype (name, nick, blurb,
+ G_PARAM_SPEC_GTYPE (spec)->is_a_type, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_INT) {
+ GParamSpecInt *ispec = G_PARAM_SPEC_INT (spec);
+ return g_param_spec_int (name, nick, blurb, ispec->minimum,
+ ispec->maximum, ispec->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_INT64) {
+ GParamSpecInt64 *ispec = G_PARAM_SPEC_INT64 (spec);
+ return g_param_spec_int64 (name, nick, blurb, ispec->minimum,
+ ispec->maximum, ispec->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_LONG) {
+ GParamSpecLong *lspec = G_PARAM_SPEC_LONG (spec);
+ return g_param_spec_long (name, nick, blurb, lspec->minimum,
+ lspec->maximum, lspec->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_OBJECT) {
+ return g_param_spec_object (name, nick, blurb, spec->value_type, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_PARAM) {
+ return g_param_spec_param (name, nick, blurb, spec->value_type, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_POINTER) {
+ return g_param_spec_pointer (name, nick, blurb, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_STRING) {
+ return g_param_spec_string (name, nick, blurb,
+ G_PARAM_SPEC_STRING (spec)->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_UCHAR) {
+ GParamSpecUChar *cspec = G_PARAM_SPEC_UCHAR (spec);
+ return g_param_spec_uchar (name, nick, blurb, cspec->minimum,
+ cspec->maximum, cspec->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_UINT) {
+ GParamSpecUInt *ispec = G_PARAM_SPEC_UINT (spec);
+ return g_param_spec_uint (name, nick, blurb, ispec->minimum,
+ ispec->maximum, ispec->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_UINT64) {
+ GParamSpecUInt64 *ispec = G_PARAM_SPEC_UINT64 (spec);
+ return g_param_spec_uint64 (name, nick, blurb, ispec->minimum,
+ ispec->maximum, ispec->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_ULONG) {
+ GParamSpecULong *lspec = G_PARAM_SPEC_ULONG (spec);
+ return g_param_spec_ulong (name, nick, blurb, lspec->minimum,
+ lspec->maximum, lspec->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_UNICHAR) {
+ return g_param_spec_unichar (name, nick, blurb,
+ G_PARAM_SPEC_UNICHAR (spec)->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_VARIANT) {
+ GParamSpecVariant *vspec = G_PARAM_SPEC_VARIANT (spec);
+ return g_param_spec_variant (name, nick, blurb, vspec->type,
+ vspec->default_value, flags);
+ }
+
+ if (G_PARAM_SPEC_TYPE (spec) == GST_TYPE_PARAM_MINI_OBJECT) {
+ return gst_param_spec_mini_object (name, nick, blurb, spec->value_type,
+ flags);
+ }
+
+ g_warning ("Unknown param type %ld for '%s'",
+ (long) G_PARAM_SPEC_TYPE (spec), name);
+ g_assert_not_reached ();
+}
+
+static void
+gst_pulse_audio_sink_class_init (GstPulseAudioSinkClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *element_class = (GstElementClass *) klass;
+ GstPulseSinkClass *psink_class =
+ GST_PULSESINK_CLASS (g_type_class_ref (GST_TYPE_PULSESINK));
+ GParamSpec **specs;
+ guint n, i, j;
+
+ gobject_class->get_property = gst_pulse_audio_sink_get_property;
+ gobject_class->set_property = gst_pulse_audio_sink_set_property;
+ gobject_class->dispose = gst_pulse_audio_sink_dispose;
+ element_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_change_state);
+
+ /* Find out how many properties we already have */
+ specs = g_object_class_list_properties (gobject_class, &klass->n_prop_own);
+ g_free (specs);
+
+ /* Proxy pulsesink's properties */
+ specs = g_object_class_list_properties (G_OBJECT_CLASS (psink_class), &n);
+ for (i = 0, j = klass->n_prop_own; i < n; i++) {
+ if (g_object_class_find_property (gobject_class,
+ g_param_spec_get_name (specs[i]))) {
+ /* We already inherited this property from a parent, skip */
+ j--;
+ } else {
+ g_object_class_install_property (gobject_class, i + j + 1,
+ param_spec_copy (specs[i]));
+ }
+ }
+
+ klass->n_prop_total = i + j;
+
+ g_free (specs);
+ g_type_class_unref (psink_class);
+}
+
+static GstPad *
+get_proxypad (GstPad * sinkpad)
+{
+ GstIterator *iter = NULL;
+ GstPad *proxypad = NULL;
+
+ iter = gst_pad_iterate_internal_links (sinkpad);
+ if (iter) {
+ if (gst_iterator_next (iter, (gpointer) & proxypad) != GST_ITERATOR_OK)
+ proxypad = NULL;
+ gst_iterator_free (iter);
+ }
+
+ return proxypad;
+}
+
+static void
+post_missing_element_message (GstPulseAudioSink * pbin, const gchar * name)
+{
+ GstMessage *msg;
+
+ msg = gst_missing_element_message_new (GST_ELEMENT_CAST (pbin), name);
+ gst_element_post_message (GST_ELEMENT_CAST (pbin), msg);
+}
+
+static void
+notify_cb (GObject * selector, GParamSpec * pspec, GstPulseAudioSink * pbin)
+{
+ g_object_notify (G_OBJECT (pbin), g_param_spec_get_name (pspec));
+}
+
+static void
+gst_pulse_audio_sink_init (GstPulseAudioSink * pbin,
+ GstPulseAudioSinkClass * klass)
+{
+ GstPadTemplate *template;
+ GstPad *pad = NULL;
+ GParamSpec **specs;
+ GString *prop;
+ guint i;
+
+ pbin->lock = g_mutex_new ();
+
+ gst_segment_init (&pbin->segment, GST_FORMAT_UNDEFINED);
+
+ pbin->psink = GST_PULSESINK (gst_element_factory_make ("pulsesink",
+ "pulseaudiosink-sink"));
+ g_assert (pbin->psink != NULL);
+
+ if (!gst_bin_add (GST_BIN (pbin), GST_ELEMENT (pbin->psink))) {
+ GST_ERROR_OBJECT (pbin, "Failed to add pulsesink to bin");
+ goto error;
+ }
+
+ pad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
+ template = gst_static_pad_template_get (&sink_template);
+ pbin->sinkpad = gst_ghost_pad_new_from_template ("sink", pad, template);
+ gst_object_unref (template);
+
+ pbin->sinkpad_old_eventfunc = GST_PAD_EVENTFUNC (pbin->sinkpad);
+ gst_pad_set_event_function (pbin->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_sink_event));
+ gst_pad_set_setcaps_function (pbin->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_sink_setcaps));
+ gst_pad_set_acceptcaps_function (pbin->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_sink_acceptcaps));
+
+ gst_element_add_pad (GST_ELEMENT (pbin), pbin->sinkpad);
+
+ if (!(pbin->sink_proxypad = get_proxypad (pbin->sinkpad)))
+ GST_ERROR_OBJECT (pbin, "Failed to get proxypad of srcpad");
+ else {
+ pbin->proxypad_old_eventfunc = GST_PAD_EVENTFUNC (pbin->sink_proxypad);
+ gst_pad_set_event_function (pbin->sink_proxypad,
+ GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_src_event));
+ }
+
+ /* Now proxy all the notify::* signals */
+ specs = g_object_class_list_properties (G_OBJECT_CLASS (klass), &i);
+ prop = g_string_sized_new (30);
+
+ for (i--; i >= klass->n_prop_own; i--) {
+ g_string_printf (prop, "notify::%s", g_param_spec_get_name (specs[i]));
+ g_signal_connect (pbin->psink, prop->str, G_CALLBACK (notify_cb), pbin);
+ }
+
+ g_string_free (prop, TRUE);
+ g_free (specs);
+
+ pbin->format_lost = FALSE;
+
+out:
+ if (pad)
+ gst_object_unref (pad);
+
+ return;
+
+error:
+ if (pbin->psink)
+ gst_object_unref (pbin->psink);
+ goto out;
+}
+
+static void
+gst_pulse_audio_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (object);
+ GstPulseAudioSinkClass *klass =
+ GST_PULSE_AUDIO_SINK_CLASS (G_OBJECT_GET_CLASS (object));
+
+ g_return_if_fail (prop_id <= klass->n_prop_total);
+
+ g_object_set_property (G_OBJECT (pbin->psink), g_param_spec_get_name (pspec),
+ value);
+}
+
+static void
+gst_pulse_audio_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (object);
+ GstPulseAudioSinkClass *klass =
+ GST_PULSE_AUDIO_SINK_CLASS (G_OBJECT_GET_CLASS (object));
+
+ g_return_if_fail (prop_id <= klass->n_prop_total);
+
+ g_object_get_property (G_OBJECT (pbin->psink), g_param_spec_get_name (pspec),
+ value);
+}
+
+static void
+gst_pulse_audio_sink_free_dbin2 (GstPulseAudioSink * pbin)
+{
+ g_signal_handler_disconnect (pbin->dbin2, pbin->pad_added_id);
+ gst_element_set_state (pbin->dbin2, GST_STATE_NULL);
+
+ gst_bin_remove (GST_BIN (pbin), pbin->dbin2);
+
+ pbin->dbin2 = NULL;
+}
+
+static void
+gst_pulse_audio_sink_dispose (GObject * object)
+{
+ GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (object);
+
+ if (pbin->lock) {
+ g_mutex_free (pbin->lock);
+ pbin->lock = NULL;
+ }
+
+ if (pbin->sink_proxypad) {
+ gst_object_unref (pbin->sink_proxypad);
+ pbin->sink_proxypad = NULL;
+ }
+
+ if (pbin->dbin2) {
+ g_signal_handler_disconnect (pbin->dbin2, pbin->pad_added_id);
+ pbin->dbin2 = NULL;
+ }
+
+ pbin->sinkpad = NULL;
+ pbin->psink = NULL;
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static gboolean
+gst_pulse_audio_sink_update_sinkpad (GstPulseAudioSink * pbin, GstPad * sinkpad)
+{
+ gboolean ret;
+
+ ret = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (pbin->sinkpad), sinkpad);
+
+ if (!ret)
+ GST_WARNING_OBJECT (pbin, "Could not update ghostpad target");
+
+ return ret;
+}
+
+static void
+distribute_running_time (GstElement * element, const GstSegment * segment)
+{
+ GstEvent *event;
+ GstPad *pad;
+
+ pad = gst_element_get_static_pad (element, "sink");
+
+ /* FIXME: Some decoders collect newsegments and send them out at once, making
+ * them lose accumulator events (and thus making dbin2_event_probe() hard to
+ * do right if we're sending these as well. We can get away with not sending
+ * these at the moment, but this should be fixed! */
+#if 0
+ if (segment->accum) {
+ event = gst_event_new_new_segment_full (FALSE, segment->rate,
+ segment->applied_rate, segment->format, 0, segment->accum, 0);
+ gst_pad_send_event (pad, event);
+ }
+#endif
+
+ event = gst_event_new_new_segment_full (FALSE, segment->rate,
+ segment->applied_rate, segment->format,
+ segment->start, segment->stop, segment->time);
+ gst_pad_send_event (pad, event);
+
+ gst_object_unref (pad);
+}
+
+static gboolean
+dbin2_event_probe (GstPad * pad, GstMiniObject * obj, gpointer data)
+{
+ GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (data);
+ GstEvent *event = GST_EVENT (obj);
+
+ if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
+ GST_DEBUG_OBJECT (pbin, "Got newsegment - dropping");
+ gst_pad_remove_event_probe (pad, pbin->event_probe_id);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+pad_added_cb (GstElement * dbin2, GstPad * pad, gpointer * data)
+{
+ GstPulseAudioSink *pbin;
+ GstPad *sinkpad = NULL;
+
+ pbin = GST_PULSE_AUDIO_SINK (data);
+ sinkpad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
+
+ GST_PULSE_AUDIO_SINK_LOCK (pbin);
+ if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
+ GST_ERROR_OBJECT (pbin, "Failed to link decodebin2 to pulsesink");
+ else
+ GST_DEBUG_OBJECT (pbin, "Linked new pad to pulsesink");
+ GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
+
+ gst_object_unref (sinkpad);
+}
+
+/* Called with pbin lock held */
+static void
+gst_pulse_audio_sink_add_dbin2 (GstPulseAudioSink * pbin)
+{
+ GstPad *sinkpad = NULL;
+
+ g_assert (pbin->dbin2 == NULL);
+
+ pbin->dbin2 = gst_element_factory_make ("decodebin2", "pulseaudiosink-dbin2");
+
+ if (!pbin->dbin2) {
+ post_missing_element_message (pbin, "decodebin2");
+ GST_ELEMENT_WARNING (pbin, CORE, MISSING_PLUGIN,
+ (_("Missing element '%s' - check your GStreamer installation."),
+ "decodebin2"), ("audio playback might fail"));
+ goto out;
+ }
+
+ if (!gst_bin_add (GST_BIN (pbin), pbin->dbin2)) {
+ GST_ERROR_OBJECT (pbin, "Failed to add decodebin2 to bin");
+ goto out;
+ }
+
+ pbin->pad_added_id = g_signal_connect (pbin->dbin2, "pad-added",
+ G_CALLBACK (pad_added_cb), pbin);
+
+ if (!gst_element_sync_state_with_parent (pbin->dbin2)) {
+ GST_ERROR_OBJECT (pbin, "Failed to set decodebin2 to parent state");
+ goto out;
+ }
+
+ /* Trap the newsegment events that we feed the decodebin and discard them */
+ sinkpad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
+ pbin->event_probe_id = gst_pad_add_event_probe_full (sinkpad,
+ G_CALLBACK (dbin2_event_probe), gst_object_ref (pbin),
+ (GDestroyNotify) gst_object_unref);
+ gst_object_unref (sinkpad);
+ sinkpad = NULL;
+
+ GST_DEBUG_OBJECT (pbin, "Distributing running time to decodebin");
+ distribute_running_time (pbin->dbin2, &pbin->segment);
+
+ sinkpad = gst_element_get_static_pad (pbin->dbin2, "sink");
+
+ gst_pulse_audio_sink_update_sinkpad (pbin, sinkpad);
+
+out:
+ if (sinkpad)
+ gst_object_unref (sinkpad);
+}
+
+static void
+update_eac3_alignment (GstPulseAudioSink * pbin)
+{
+ GstCaps *caps = gst_pad_peer_get_caps_reffed (pbin->sinkpad);
+ GstStructure *st;
+
+ if (!caps)
+ return;
+
+ st = gst_caps_get_structure (caps, 0);
+
+ if (g_str_equal (gst_structure_get_name (st), "audio/x-eac3")) {
+ GstStructure *event_st = gst_structure_new ("ac3parse-set-alignment",
+ "alignment", G_TYPE_STRING, pbin->dbin2 ? "frame" : "iec61937", NULL);
+
+ if (!gst_pad_push_event (pbin->sinkpad,
+ gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, event_st)))
+ GST_WARNING_OBJECT (pbin->sinkpad, "Could not update alignment");
+ }
+
+ gst_caps_unref (caps);
+}
+
+static void
+proxypad_blocked_cb (GstPad * pad, gboolean blocked, gpointer data)
+{
+ GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (data);
+ GstCaps *caps;
+ GstPad *sinkpad = NULL;
+
+ if (!blocked) {
+ /* Unblocked, don't need to do anything */
+ GST_DEBUG_OBJECT (pbin, "unblocked");
+ return;
+ }
+
+ GST_DEBUG_OBJECT (pbin, "blocked");
+
+ GST_PULSE_AUDIO_SINK_LOCK (pbin);
+
+ if (!pbin->format_lost) {
+ sinkpad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
+
+ if (GST_PAD_CAPS (pbin->sinkpad)) {
+ /* See if we already got caps on our sinkpad */
+ caps = gst_caps_ref (GST_PAD_CAPS (pbin->sinkpad));
+ } else {
+ /* We haven't, so get caps from upstream */
+ caps = gst_pad_get_caps_reffed (pad);
+ }
+
+ if (gst_pad_accept_caps (sinkpad, caps)) {
+ if (pbin->dbin2) {
+ GST_DEBUG_OBJECT (pbin, "Removing decodebin");
+ gst_pulse_audio_sink_free_dbin2 (pbin);
+ gst_pulse_audio_sink_update_sinkpad (pbin, sinkpad);
+ } else
+ GST_DEBUG_OBJECT (pbin, "Doing nothing");
+
+ gst_caps_unref (caps);
+ gst_object_unref (sinkpad);
+ goto done;
+ }
+ /* pulsesink doesn't accept the incoming caps, so add a decodebin
+ * (potentially after removing the existing once, since decodebin2 can't
+ * renegotiate). */
+ } else {
+ /* Format lost, proceed to try plugging a decodebin */
+ pbin->format_lost = FALSE;
+ }
+
+ if (pbin->dbin2 != NULL) {
+ /* decodebin2 doesn't support reconfiguration, so throw this one away and
+ * create a new one. */
+ gst_pulse_audio_sink_free_dbin2 (pbin);
+ }
+
+ GST_DEBUG_OBJECT (pbin, "Adding decodebin");
+ gst_pulse_audio_sink_add_dbin2 (pbin);
+
+done:
+ update_eac3_alignment (pbin);
+
+ gst_pad_set_blocked_async_full (pad, FALSE, proxypad_blocked_cb,
+ gst_object_ref (pbin), (GDestroyNotify) gst_object_unref);
+
+ GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
+}
+
+static gboolean
+gst_pulse_audio_sink_src_event (GstPad * pad, GstEvent * event)
+{
+ GstPulseAudioSink *pbin = NULL;
+ GstPad *ghostpad = NULL;
+ gboolean ret = FALSE;
+
+ ghostpad = GST_PAD_CAST (gst_pad_get_parent (pad));
+ if (G_UNLIKELY (!ghostpad)) {
+ GST_WARNING_OBJECT (pad, "Could not get ghostpad");
+ goto out;
+ }
+
+ pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (ghostpad));
+ if (G_UNLIKELY (!pbin)) {
+ GST_WARNING_OBJECT (pad, "Could not get pulseaudiosink");
+ goto out;
+ }
+
+ if (G_UNLIKELY (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) &&
+ (gst_event_has_name (event, "pulse-format-lost") ||
+ gst_event_has_name (event, "pulse-sink-changed"))) {
+ g_return_val_if_fail (pad->mode != GST_ACTIVATE_PULL, FALSE);
+
+ GST_PULSE_AUDIO_SINK_LOCK (pbin);
+ if (gst_event_has_name (event, "pulse-format-lost"))
+ pbin->format_lost = TRUE;
+
+ if (!gst_pad_is_blocked (pad))
+ gst_pad_set_blocked_async_full (pad, TRUE, proxypad_blocked_cb,
+ gst_object_ref (pbin), (GDestroyNotify) gst_object_unref);
+ GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
+
+ ret = TRUE;
+ } else if (pbin->proxypad_old_eventfunc) {
+ ret = pbin->proxypad_old_eventfunc (pad, event);
+ event = NULL;
+ }
+
+out:
+ if (ghostpad)
+ gst_object_unref (ghostpad);
+ if (pbin)
+ gst_object_unref (pbin);
+ if (event)
+ gst_event_unref (event);
+
+ return ret;
+}
+
+static gboolean
+gst_pulse_audio_sink_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (pad));
+ gboolean ret;
+
+ ret = pbin->sinkpad_old_eventfunc (pad, gst_event_ref (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_NEWSEGMENT:
+ {
+ GstFormat format;
+ gdouble rate, arate;
+ gint64 start, stop, time;
+ gboolean update;
+
+ GST_PULSE_AUDIO_SINK_LOCK (pbin);
+ gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
+ &start, &stop, &time);
+
+ GST_DEBUG_OBJECT (pbin,
+ "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT
+ ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT,
+ update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
+ GST_TIME_ARGS (time));
+
+ if (format == GST_FORMAT_TIME) {
+ /* Store the values for feeding to sub-elements */
+ gst_segment_set_newsegment_full (&pbin->segment, update,
+ rate, arate, format, start, stop, time);
+ } else {
+ GST_WARNING_OBJECT (pbin, "Got a non-TIME format segment");
+ gst_segment_init (&pbin->segment, GST_FORMAT_TIME);
+ }
+ GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
+
+ break;
+ }
+
+ case GST_EVENT_FLUSH_STOP:
+ GST_PULSE_AUDIO_SINK_LOCK (pbin);
+ gst_segment_init (&pbin->segment, GST_FORMAT_UNDEFINED);
+ GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
+ break;
+
+ default:
+ break;
+ }
+
+ gst_object_unref (pbin);
+ gst_event_unref (event);
+
+ return ret;
+}
+
+/* The bin's acceptcaps should be exactly equivalent to a pulsesink that is
+ * connected to a sink that supports all the formats in template caps. This
+ * means that upstream will have to have everything possibly upto a parser
+ * plugged and we plugin a decoder whenever required. */
+static gboolean
+gst_pulse_audio_sink_sink_acceptcaps (GstPad * pad, GstCaps * caps)
+{
+ GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (pad));
+ GstRingBufferSpec spec = { 0 };
+ const GstStructure *st;
+ GstCaps *pad_caps = NULL;
+ gboolean ret = FALSE;
+
+ pad_caps = gst_pad_get_caps_reffed (pad);
+ if (!pad_caps || !gst_caps_can_intersect (pad_caps, caps))
+ goto out;
+
+ /* If we've not got fixed caps, creating a stream might fail, so let's just
+ * return from here with default acceptcaps behaviour */
+ if (!gst_caps_is_fixed (caps))
+ goto out;
+
+ spec.latency_time = GST_BASE_AUDIO_SINK (pbin->psink)->latency_time;
+ if (!gst_ring_buffer_parse_caps (&spec, caps))
+ goto out;
+
+ /* Make sure non-raw input is framed (one frame per buffer) and can be
+ * payloaded */
+ st = gst_caps_get_structure (caps, 0);
+
+ if (!g_str_has_prefix (gst_structure_get_name (st), "audio/x-raw")) {
+ gboolean framed = FALSE, parsed = FALSE;
+
+ gst_structure_get_boolean (st, "framed", &framed);
+ gst_structure_get_boolean (st, "parsed", &parsed);
+ if ((!framed && !parsed) || gst_audio_iec61937_frame_size (&spec) <= 0)
+ goto out;
+ }
+
+ ret = TRUE;
+
+out:
+ if (pad_caps)
+ gst_caps_unref (pad_caps);
+
+ gst_object_unref (pbin);
+
+ return ret;
+}
+
+static gboolean
+gst_pulse_audio_sink_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (pad));
+ gboolean ret = TRUE;
+
+ GST_PULSE_AUDIO_SINK_LOCK (pbin);
+
+ if (!gst_pad_is_blocked (pbin->sinkpad))
+ gst_pad_set_blocked_async_full (pbin->sink_proxypad, TRUE,
+ proxypad_blocked_cb, gst_object_ref (pbin),
+ (GDestroyNotify) gst_object_unref);
+
+ GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
+
+ gst_object_unref (pbin);
+
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_pulse_audio_sink_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (element);
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ /* Nothing to do for upward transitions */
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ GST_PULSE_AUDIO_SINK_LOCK (pbin);
+ if (gst_pad_is_blocked (pbin->sinkpad)) {
+ gst_pad_set_blocked_async_full (pbin->sink_proxypad, FALSE,
+ proxypad_blocked_cb, gst_object_ref (pbin),
+ (GDestroyNotify) gst_object_unref);
+ }
+ GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
+ break;
+
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret != GST_STATE_CHANGE_SUCCESS) {
+ GST_DEBUG_OBJECT (pbin, "Base class returned %d on state change", ret);
+ goto out;
+ }
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ GST_PULSE_AUDIO_SINK_LOCK (pbin);
+ gst_segment_init (&pbin->segment, GST_FORMAT_UNDEFINED);
+
+ if (pbin->dbin2) {
+ GstPad *pad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink),
+ "sink");
+
+ gst_pulse_audio_sink_free_dbin2 (pbin);
+ gst_pulse_audio_sink_update_sinkpad (pbin, pad);
+
+ gst_object_unref (pad);
+
+ }
+ GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
+
+ break;
+
+ default:
+ break;
+ }
+
+out:
+ return ret;
+}
+
+#endif /* HAVE_PULSE_1_0 */
diff --git a/ext/pulse/pulsemixer.c b/ext/pulse/pulsemixer.c
new file mode 100644
index 0000000..96468ce
--- /dev/null
+++ b/ext/pulse/pulsemixer.c
@@ -0,0 +1,282 @@
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+/**
+ * SECTION:element-pulsemixer
+ * @see_also: pulsesrc, pulsesink
+ *
+ * This element lets you adjust sound input and output levels for the
+ * PulseAudio sound server. It supports the GstMixer interface, which can be
+ * used to obtain a list of available mixer tracks. Set the mixer element to
+ * READY state before using the GstMixer interface on it.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * <para>
+ * pulsemixer can't be used in a sensible way in gst-launch.
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "pulsemixer.h"
+
+enum
+{
+ PROP_SERVER = 1,
+ PROP_DEVICE,
+ PROP_DEVICE_NAME
+};
+
+GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
+#define GST_CAT_DEFAULT pulse_debug
+
+static void gst_pulsemixer_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_pulsemixer_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_pulsemixer_finalize (GObject * object);
+
+static GstStateChangeReturn gst_pulsemixer_change_state (GstElement * element,
+ GstStateChange transition);
+
+static void gst_pulsemixer_init_interfaces (GType type);
+
+GST_IMPLEMENT_PULSEMIXER_CTRL_METHODS (GstPulseMixer, gst_pulsemixer);
+GST_IMPLEMENT_PULSEPROBE_METHODS (GstPulseMixer, gst_pulsemixer);
+GST_BOILERPLATE_FULL (GstPulseMixer, gst_pulsemixer, GstElement,
+ GST_TYPE_ELEMENT, gst_pulsemixer_init_interfaces);
+
+static gboolean
+gst_pulsemixer_interface_supported (GstImplementsInterface
+ * iface, GType interface_type)
+{
+ GstPulseMixer *this = GST_PULSEMIXER (iface);
+
+ if (interface_type == GST_TYPE_MIXER && this->mixer)
+ return TRUE;
+
+ if (interface_type == GST_TYPE_PROPERTY_PROBE && this->probe)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+gst_pulsemixer_implements_interface_init (GstImplementsInterfaceClass * klass)
+{
+ klass->supported = gst_pulsemixer_interface_supported;
+}
+
+static void
+gst_pulsemixer_init_interfaces (GType type)
+{
+ static const GInterfaceInfo implements_iface_info = {
+ (GInterfaceInitFunc) gst_pulsemixer_implements_interface_init,
+ NULL,
+ NULL,
+ };
+ static const GInterfaceInfo mixer_iface_info = {
+ (GInterfaceInitFunc) gst_pulsemixer_mixer_interface_init,
+ NULL,
+ NULL,
+ };
+ static const GInterfaceInfo probe_iface_info = {
+ (GInterfaceInitFunc) gst_pulsemixer_property_probe_interface_init,
+ NULL,
+ NULL,
+ };
+
+ g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
+ &implements_iface_info);
+ g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info);
+ g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
+ &probe_iface_info);
+}
+
+static void
+gst_pulsemixer_base_init (gpointer g_class)
+{
+ gst_element_class_set_details_simple (GST_ELEMENT_CLASS (g_class),
+ "PulseAudio Mixer",
+ "Generic/Audio",
+ "Control sound input and output levels for PulseAudio",
+ "Lennart Poettering");
+}
+
+static void
+gst_pulsemixer_class_init (GstPulseMixerClass * g_class)
+{
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_pulsemixer_change_state);
+
+ gobject_class->finalize = gst_pulsemixer_finalize;
+ gobject_class->get_property = gst_pulsemixer_get_property;
+ gobject_class->set_property = gst_pulsemixer_set_property;
+
+ g_object_class_install_property (gobject_class,
+ PROP_SERVER,
+ g_param_spec_string ("server", "Server",
+ "The PulseAudio server to connect to", NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class,
+ PROP_DEVICE,
+ g_param_spec_string ("device", "Device",
+ "The PulseAudio sink or source to control", NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class,
+ PROP_DEVICE_NAME,
+ g_param_spec_string ("device-name", "Device name",
+ "Human-readable name of the sound device", NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_pulsemixer_init (GstPulseMixer * this, GstPulseMixerClass * g_class)
+{
+ this->mixer = NULL;
+ this->server = NULL;
+ this->device = NULL;
+
+ this->probe =
+ gst_pulseprobe_new (G_OBJECT (this), G_OBJECT_GET_CLASS (this),
+ PROP_DEVICE, this->device, TRUE, TRUE);
+}
+
+static void
+gst_pulsemixer_finalize (GObject * object)
+{
+ GstPulseMixer *this = GST_PULSEMIXER (object);
+
+ g_free (this->server);
+ g_free (this->device);
+
+ if (this->mixer) {
+ gst_pulsemixer_ctrl_free (this->mixer);
+ this->mixer = NULL;
+ }
+
+ if (this->probe) {
+ gst_pulseprobe_free (this->probe);
+ this->probe = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_pulsemixer_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstPulseMixer *this = GST_PULSEMIXER (object);
+
+ switch (prop_id) {
+ case PROP_SERVER:
+ g_free (this->server);
+ this->server = g_value_dup_string (value);
+
+ if (this->probe)
+ gst_pulseprobe_set_server (this->probe, this->server);
+
+ break;
+
+ case PROP_DEVICE:
+ g_free (this->device);
+ this->device = g_value_dup_string (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_pulsemixer_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstPulseMixer *this = GST_PULSEMIXER (object);
+
+ switch (prop_id) {
+ case PROP_SERVER:
+ g_value_set_string (value, this->server);
+ break;
+ case PROP_DEVICE:
+ g_value_set_string (value, this->device);
+ break;
+ case PROP_DEVICE_NAME:
+ if (this->mixer) {
+ char *t = g_strdup_printf ("%s: %s",
+ this->mixer->type == GST_PULSEMIXER_SINK ? "Playback" : "Capture",
+ this->mixer->description);
+ g_value_take_string (value, t);
+ } else
+ g_value_set_string (value, NULL);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstStateChangeReturn
+gst_pulsemixer_change_state (GstElement * element, GstStateChange transition)
+{
+ GstPulseMixer *this = GST_PULSEMIXER (element);
+ GstStateChangeReturn res;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!this->mixer)
+ this->mixer =
+ gst_pulsemixer_ctrl_new (G_OBJECT (this), this->server,
+ this->device, GST_PULSEMIXER_UNKNOWN);
+ break;
+ default:
+ ;
+ }
+
+ res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ if (this->mixer) {
+ gst_pulsemixer_ctrl_free (this->mixer);
+ this->mixer = NULL;
+ }
+ break;
+ default:
+ ;
+ }
+
+ return res;
+}
diff --git a/ext/pulse/pulsemixer.h b/ext/pulse/pulsemixer.h
new file mode 100644
index 0000000..7ba3d2f
--- /dev/null
+++ b/ext/pulse/pulsemixer.h
@@ -0,0 +1,68 @@
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifndef __GST_PULSEMIXER_H__
+#define __GST_PULSEMIXER_H__
+
+#include <gst/gst.h>
+
+#include <pulse/pulseaudio.h>
+#include <pulse/thread-mainloop.h>
+
+#include "pulsemixerctrl.h"
+#include "pulseprobe.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PULSEMIXER \
+ (gst_pulsemixer_get_type())
+#define GST_PULSEMIXER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PULSEMIXER,GstPulseMixer))
+#define GST_PULSEMIXER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PULSEMIXER,GstPulseMixerClass))
+#define GST_IS_PULSEMIXER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PULSEMIXER))
+#define GST_IS_PULSEMIXER_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PULSEMIXER))
+
+typedef struct _GstPulseMixer GstPulseMixer;
+typedef struct _GstPulseMixerClass GstPulseMixerClass;
+
+struct _GstPulseMixer
+{
+ GstElement parent;
+
+ gchar *server, *device;
+
+ GstPulseMixerCtrl *mixer;
+ GstPulseProbe *probe;
+};
+
+struct _GstPulseMixerClass
+{
+ GstElementClass parent_class;
+};
+
+GType gst_pulsemixer_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_PULSEMIXER_H__ */
diff --git a/ext/pulse/pulsemixerctrl.c b/ext/pulse/pulsemixerctrl.c
new file mode 100644
index 0000000..220c8d0
--- /dev/null
+++ b/ext/pulse/pulsemixerctrl.c
@@ -0,0 +1,640 @@
+/*-*- Mode: C; c-basic-offset: 2 -*-*/
+
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "pulsemixerctrl.h"
+#include "pulsemixertrack.h"
+#include "pulseutil.h"
+
+GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
+#define GST_CAT_DEFAULT pulse_debug
+
+static void
+gst_pulsemixer_ctrl_context_state_cb (pa_context * context, void *userdata)
+{
+ GstPulseMixerCtrl *c = GST_PULSEMIXER_CTRL (userdata);
+
+ /* Called from the background thread! */
+
+ switch (pa_context_get_state (context)) {
+ case PA_CONTEXT_READY:
+ case PA_CONTEXT_TERMINATED:
+ case PA_CONTEXT_FAILED:
+ pa_threaded_mainloop_signal (c->mainloop, 0);
+ break;
+
+ case PA_CONTEXT_UNCONNECTED:
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ break;
+ }
+}
+
+static void
+gst_pulsemixer_ctrl_sink_info_cb (pa_context * context, const pa_sink_info * i,
+ int eol, void *userdata)
+{
+ GstPulseMixerCtrl *c = userdata;
+ gboolean vol_chg = FALSE;
+ gboolean old_mute;
+
+ /* Called from the background thread! */
+
+ if (c->outstandig_queries > 0)
+ c->outstandig_queries--;
+
+ if (c->ignore_queries > 0 || c->time_event) {
+
+ if (c->ignore_queries > 0)
+ c->ignore_queries--;
+
+ return;
+ }
+
+ if (!i && eol < 0) {
+ c->operation_success = FALSE;
+ pa_threaded_mainloop_signal (c->mainloop, 0);
+ return;
+ }
+
+ if (eol)
+ return;
+
+ g_free (c->name);
+ g_free (c->description);
+ c->name = g_strdup (i->name);
+ c->description = g_strdup (i->description);
+ c->index = i->index;
+ c->channel_map = i->channel_map;
+ vol_chg = !pa_cvolume_equal (&c->volume, &i->volume);
+ c->volume = i->volume;
+ old_mute = c->muted;
+ c->muted = !!i->mute;
+ c->type = GST_PULSEMIXER_SINK;
+
+ if (c->track) {
+ GstMixerTrackFlags flags = c->track->flags;
+
+ flags =
+ (flags & ~GST_MIXER_TRACK_MUTE) | (c->muted ? GST_MIXER_TRACK_MUTE : 0);
+ c->track->flags = flags;
+ }
+
+ c->operation_success = TRUE;
+ pa_threaded_mainloop_signal (c->mainloop, 0);
+
+ if (vol_chg && c->track) {
+ gint volumes[PA_CHANNELS_MAX];
+ gint i;
+ for (i = 0; i < c->volume.channels; i++)
+ volumes[i] = (gint) (c->volume.values[i]);
+ GST_LOG_OBJECT (c->object, "Sending volume change notification");
+ gst_mixer_volume_changed (GST_MIXER (c->object), c->track, volumes);
+ }
+ if ((c->muted != old_mute) && c->track) {
+ GST_LOG_OBJECT (c->object, "Sending mute toggled notification");
+ gst_mixer_mute_toggled (GST_MIXER (c->object), c->track, c->muted);
+ }
+}
+
+static void
+gst_pulsemixer_ctrl_source_info_cb (pa_context * context,
+ const pa_source_info * i, int eol, void *userdata)
+{
+ GstPulseMixerCtrl *c = userdata;
+ gboolean vol_chg = FALSE;
+ gboolean old_mute;
+
+ /* Called from the background thread! */
+
+ if (c->outstandig_queries > 0)
+ c->outstandig_queries--;
+
+ if (c->ignore_queries > 0 || c->time_event) {
+
+ if (c->ignore_queries > 0)
+ c->ignore_queries--;
+
+ return;
+ }
+
+ if (!i && eol < 0) {
+ c->operation_success = FALSE;
+ pa_threaded_mainloop_signal (c->mainloop, 0);
+ return;
+ }
+
+ if (eol)
+ return;
+
+ g_free (c->name);
+ g_free (c->description);
+ c->name = g_strdup (i->name);
+ c->description = g_strdup (i->description);
+ c->index = i->index;
+ c->channel_map = i->channel_map;
+ vol_chg = !pa_cvolume_equal (&c->volume, &i->volume);
+ c->volume = i->volume;
+ old_mute = c->muted;
+ c->muted = !!i->mute;
+ c->type = GST_PULSEMIXER_SOURCE;
+
+ if (c->track) {
+ GstMixerTrackFlags flags = c->track->flags;
+
+ flags =
+ (flags & ~GST_MIXER_TRACK_MUTE) | (c->muted ? GST_MIXER_TRACK_MUTE : 0);
+ c->track->flags = flags;
+ }
+
+ c->operation_success = TRUE;
+ pa_threaded_mainloop_signal (c->mainloop, 0);
+
+ if (vol_chg && c->track) {
+ gint volumes[PA_CHANNELS_MAX];
+ gint i;
+ for (i = 0; i < c->volume.channels; i++)
+ volumes[i] = (gint) (c->volume.values[i]);
+ GST_LOG_OBJECT (c->object, "Sending volume change notification");
+ gst_mixer_volume_changed (GST_MIXER (c->object), c->track, volumes);
+ }
+ if ((c->muted != old_mute) && c->track) {
+ GST_LOG_OBJECT (c->object, "Sending mute toggled notification");
+ gst_mixer_mute_toggled (GST_MIXER (c->object), c->track, c->muted);
+ }
+}
+
+static void
+gst_pulsemixer_ctrl_subscribe_cb (pa_context * context,
+ pa_subscription_event_type_t t, uint32_t idx, void *userdata)
+{
+ GstPulseMixerCtrl *c = GST_PULSEMIXER_CTRL (userdata);
+ pa_operation *o = NULL;
+
+ /* Called from the background thread! */
+
+ if (c->index != idx)
+ return;
+
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
+ return;
+
+ if (c->type == GST_PULSEMIXER_SINK)
+ o = pa_context_get_sink_info_by_index (c->context, c->index,
+ gst_pulsemixer_ctrl_sink_info_cb, c);
+ else
+ o = pa_context_get_source_info_by_index (c->context, c->index,
+ gst_pulsemixer_ctrl_source_info_cb, c);
+
+ if (!o) {
+ GST_WARNING_OBJECT (c->object, "Failed to get sink info: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ return;
+ }
+
+ pa_operation_unref (o);
+
+ c->outstandig_queries++;
+}
+
+static void
+gst_pulsemixer_ctrl_success_cb (pa_context * context, int success,
+ void *userdata)
+{
+ GstPulseMixerCtrl *c = (GstPulseMixerCtrl *) userdata;
+
+ c->operation_success = !!success;
+ pa_threaded_mainloop_signal (c->mainloop, 0);
+}
+
+#define CHECK_DEAD_GOTO(c, label) \
+ G_STMT_START { \
+ if (!(c)->context || \
+ !PA_CONTEXT_IS_GOOD(pa_context_get_state((c)->context))) { \
+ GST_WARNING_OBJECT ((c)->object, "Not connected: %s", \
+ (c)->context ? pa_strerror(pa_context_errno((c)->context)) : "NULL"); \
+ goto label; \
+ } \
+ } G_STMT_END
+
+static gboolean
+gst_pulsemixer_ctrl_open (GstPulseMixerCtrl * c)
+{
+ int e;
+ gchar *name;
+ pa_operation *o = NULL;
+
+ g_assert (c);
+
+ GST_DEBUG_OBJECT (c->object, "ctrl open");
+
+ c->mainloop = pa_threaded_mainloop_new ();
+ if (!c->mainloop)
+ return FALSE;
+
+ e = pa_threaded_mainloop_start (c->mainloop);
+ if (e < 0)
+ return FALSE;
+
+ name = gst_pulse_client_name ();
+
+ pa_threaded_mainloop_lock (c->mainloop);
+
+ if (!(c->context =
+ pa_context_new (pa_threaded_mainloop_get_api (c->mainloop), name))) {
+ GST_WARNING_OBJECT (c->object, "Failed to create context");
+ goto unlock_and_fail;
+ }
+
+ pa_context_set_state_callback (c->context,
+ gst_pulsemixer_ctrl_context_state_cb, c);
+ pa_context_set_subscribe_callback (c->context,
+ gst_pulsemixer_ctrl_subscribe_cb, c);
+
+ if (pa_context_connect (c->context, c->server, 0, NULL) < 0) {
+ GST_WARNING_OBJECT (c->object, "Failed to connect context: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+
+ /* Wait until the context is ready */
+ while (pa_context_get_state (c->context) != PA_CONTEXT_READY) {
+ CHECK_DEAD_GOTO (c, unlock_and_fail);
+ pa_threaded_mainloop_wait (c->mainloop);
+ }
+
+ /* Subscribe to events */
+ if (!(o =
+ pa_context_subscribe (c->context,
+ PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE,
+ gst_pulsemixer_ctrl_success_cb, c))) {
+ GST_WARNING_OBJECT (c->object, "Failed to subscribe to events: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+
+ c->operation_success = FALSE;
+ while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
+ CHECK_DEAD_GOTO (c, unlock_and_fail);
+ pa_threaded_mainloop_wait (c->mainloop);
+ }
+
+ if (!c->operation_success) {
+ GST_WARNING_OBJECT (c->object, "Failed to subscribe to events: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+ pa_operation_unref (o);
+ o = NULL;
+
+ /* Get sink info */
+
+ if (c->type == GST_PULSEMIXER_UNKNOWN || c->type == GST_PULSEMIXER_SINK) {
+ GST_WARNING_OBJECT (c->object, "Get info for '%s'", c->device);
+ if (!(o =
+ pa_context_get_sink_info_by_name (c->context, c->device,
+ gst_pulsemixer_ctrl_sink_info_cb, c))) {
+ GST_WARNING_OBJECT (c->object, "Failed to get sink info: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+
+ c->operation_success = FALSE;
+ while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
+ CHECK_DEAD_GOTO (c, unlock_and_fail);
+ pa_threaded_mainloop_wait (c->mainloop);
+ }
+
+ pa_operation_unref (o);
+ o = NULL;
+
+ if (!c->operation_success && (c->type == GST_PULSEMIXER_SINK
+ || pa_context_errno (c->context) != PA_ERR_NOENTITY)) {
+ GST_WARNING_OBJECT (c->object, "Failed to get sink info: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+ }
+
+ if (c->type == GST_PULSEMIXER_UNKNOWN || c->type == GST_PULSEMIXER_SOURCE) {
+ if (!(o =
+ pa_context_get_source_info_by_name (c->context, c->device,
+ gst_pulsemixer_ctrl_source_info_cb, c))) {
+ GST_WARNING_OBJECT (c->object, "Failed to get source info: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+
+ c->operation_success = FALSE;
+ while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
+ CHECK_DEAD_GOTO (c, unlock_and_fail);
+ pa_threaded_mainloop_wait (c->mainloop);
+ }
+
+ pa_operation_unref (o);
+ o = NULL;
+
+ if (!c->operation_success) {
+ GST_WARNING_OBJECT (c->object, "Failed to get source info: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+ }
+
+ g_assert (c->type != GST_PULSEMIXER_UNKNOWN);
+
+ c->track = gst_pulsemixer_track_new (c);
+ c->tracklist = g_list_append (c->tracklist, c->track);
+
+ pa_threaded_mainloop_unlock (c->mainloop);
+ g_free (name);
+
+ return TRUE;
+
+unlock_and_fail:
+
+ if (o)
+ pa_operation_unref (o);
+
+ if (c->mainloop)
+ pa_threaded_mainloop_unlock (c->mainloop);
+
+ g_free (name);
+
+ return FALSE;
+}
+
+static void
+gst_pulsemixer_ctrl_close (GstPulseMixerCtrl * c)
+{
+ g_assert (c);
+
+ GST_DEBUG_OBJECT (c->object, "ctrl close");
+
+ if (c->mainloop)
+ pa_threaded_mainloop_stop (c->mainloop);
+
+ if (c->context) {
+ pa_context_disconnect (c->context);
+ pa_context_unref (c->context);
+ c->context = NULL;
+ }
+
+ if (c->mainloop) {
+ pa_threaded_mainloop_free (c->mainloop);
+ c->mainloop = NULL;
+ c->time_event = NULL;
+ }
+
+ if (c->tracklist) {
+ g_list_free (c->tracklist);
+ c->tracklist = NULL;
+ }
+
+ if (c->track) {
+ GST_PULSEMIXER_TRACK (c->track)->control = NULL;
+ g_object_unref (c->track);
+ c->track = NULL;
+ }
+}
+
+GstPulseMixerCtrl *
+gst_pulsemixer_ctrl_new (GObject * object, const gchar * server,
+ const gchar * device, GstPulseMixerType type)
+{
+ GstPulseMixerCtrl *c = NULL;
+ g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE ((object),
+ GST_TYPE_MIXER), c);
+
+ GST_DEBUG_OBJECT (object, "new mixer ctrl for %s", device);
+ c = g_new (GstPulseMixerCtrl, 1);
+ c->object = g_object_ref (object);
+ c->tracklist = NULL;
+ c->server = g_strdup (server);
+ c->device = g_strdup (device);
+ c->mainloop = NULL;
+ c->context = NULL;
+ c->track = NULL;
+ c->ignore_queries = c->outstandig_queries = 0;
+
+ pa_cvolume_mute (&c->volume, PA_CHANNELS_MAX);
+ pa_channel_map_init (&c->channel_map);
+ c->muted = FALSE;
+ c->index = PA_INVALID_INDEX;
+ c->type = type;
+ c->name = NULL;
+ c->description = NULL;
+
+ c->time_event = NULL;
+ c->update_volume = c->update_mute = FALSE;
+
+ if (!(gst_pulsemixer_ctrl_open (c))) {
+ gst_pulsemixer_ctrl_free (c);
+ return NULL;
+ }
+
+ return c;
+}
+
+void
+gst_pulsemixer_ctrl_free (GstPulseMixerCtrl * c)
+{
+ g_assert (c);
+
+ gst_pulsemixer_ctrl_close (c);
+
+ g_free (c->server);
+ g_free (c->device);
+ g_free (c->name);
+ g_free (c->description);
+ g_object_unref (c->object);
+ g_free (c);
+}
+
+const GList *
+gst_pulsemixer_ctrl_list_tracks (GstPulseMixerCtrl * c)
+{
+ g_assert (c);
+
+ return c->tracklist;
+}
+
+static void
+gst_pulsemixer_ctrl_timeout_event (pa_mainloop_api * a, pa_time_event * e,
+ const struct timeval *tv, void *userdata)
+{
+ pa_operation *o;
+ GstPulseMixerCtrl *c = GST_PULSEMIXER_CTRL (userdata);
+
+ if (c->update_volume) {
+ if (c->type == GST_PULSEMIXER_SINK)
+ o = pa_context_set_sink_volume_by_index (c->context, c->index, &c->volume,
+ NULL, NULL);
+ else
+ o = pa_context_set_source_volume_by_index (c->context, c->index,
+ &c->volume, NULL, NULL);
+
+ if (!o)
+ GST_WARNING_OBJECT (c->object, "Failed to set device volume: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ else
+ pa_operation_unref (o);
+
+ c->update_volume = FALSE;
+ }
+
+ if (c->update_mute) {
+ if (c->type == GST_PULSEMIXER_SINK)
+ o = pa_context_set_sink_mute_by_index (c->context, c->index, c->muted,
+ NULL, NULL);
+ else
+ o = pa_context_set_source_mute_by_index (c->context, c->index, c->muted,
+ NULL, NULL);
+
+ if (!o)
+ GST_WARNING_OBJECT (c->object, "Failed to set device mute: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ else
+ pa_operation_unref (o);
+
+ c->update_mute = FALSE;
+ }
+
+ /* Make sure that all outstanding queries are being ignored */
+ c->ignore_queries = c->outstandig_queries;
+
+ g_assert (e == c->time_event);
+ a->time_free (e);
+ c->time_event = NULL;
+}
+
+#define UPDATE_DELAY 50000
+
+static void
+restart_time_event (GstPulseMixerCtrl * c)
+{
+ struct timeval tv;
+ pa_mainloop_api *api;
+
+ g_assert (c);
+
+ if (c->time_event)
+ return;
+
+ /* Updating the volume too often will cause a lot of traffic
+ * when accessing a networked server. Therefore we make sure
+ * to update the volume only once every 50ms */
+
+ api = pa_threaded_mainloop_get_api (c->mainloop);
+
+ c->time_event =
+ api->time_new (api, pa_timeval_add (pa_gettimeofday (&tv), UPDATE_DELAY),
+ gst_pulsemixer_ctrl_timeout_event, c);
+}
+
+void
+gst_pulsemixer_ctrl_set_volume (GstPulseMixerCtrl * c, GstMixerTrack * track,
+ gint * volumes)
+{
+ pa_cvolume v;
+ int i;
+
+ g_assert (c);
+ g_assert (track == c->track);
+
+ pa_threaded_mainloop_lock (c->mainloop);
+
+ for (i = 0; i < c->channel_map.channels; i++)
+ v.values[i] = (pa_volume_t) volumes[i];
+
+ v.channels = c->channel_map.channels;
+
+ c->volume = v;
+ c->update_volume = TRUE;
+
+ restart_time_event (c);
+
+ pa_threaded_mainloop_unlock (c->mainloop);
+}
+
+void
+gst_pulsemixer_ctrl_get_volume (GstPulseMixerCtrl * c, GstMixerTrack * track,
+ gint * volumes)
+{
+ int i;
+
+ g_assert (c);
+ g_assert (track == c->track);
+
+ pa_threaded_mainloop_lock (c->mainloop);
+
+ for (i = 0; i < c->channel_map.channels; i++)
+ volumes[i] = c->volume.values[i];
+
+ pa_threaded_mainloop_unlock (c->mainloop);
+}
+
+void
+gst_pulsemixer_ctrl_set_record (GstPulseMixerCtrl * c, GstMixerTrack * track,
+ gboolean record)
+{
+ g_assert (c);
+ g_assert (track == c->track);
+}
+
+void
+gst_pulsemixer_ctrl_set_mute (GstPulseMixerCtrl * c, GstMixerTrack * track,
+ gboolean mute)
+{
+ g_assert (c);
+ g_assert (track == c->track);
+
+ pa_threaded_mainloop_lock (c->mainloop);
+
+ c->muted = mute;
+ c->update_mute = TRUE;
+
+ if (c->track) {
+ GstMixerTrackFlags flags = c->track->flags;
+
+ flags =
+ (flags & ~GST_MIXER_TRACK_MUTE) | (c->muted ? GST_MIXER_TRACK_MUTE : 0);
+ c->track->flags = flags;
+ }
+
+ restart_time_event (c);
+
+ pa_threaded_mainloop_unlock (c->mainloop);
+}
+
+GstMixerFlags
+gst_pulsemixer_ctrl_get_mixer_flags (GstPulseMixerCtrl * mixer)
+{
+ return GST_MIXER_FLAG_AUTO_NOTIFICATIONS;
+}
diff --git a/ext/pulse/pulsemixerctrl.h b/ext/pulse/pulsemixerctrl.h
new file mode 100644
index 0000000..c1d1e85
--- /dev/null
+++ b/ext/pulse/pulsemixerctrl.h
@@ -0,0 +1,175 @@
+/*-*- Mode: C; c-basic-offset: 2 -*-*/
+
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifndef __GST_PULSEMIXERCTRL_H__
+#define __GST_PULSEMIXERCTRL_H__
+
+#include <gst/gst.h>
+#include <gst/interfaces/mixer.h>
+
+#include <pulse/pulseaudio.h>
+#include <pulse/thread-mainloop.h>
+
+G_BEGIN_DECLS
+
+#define GST_PULSEMIXER_CTRL(obj) ((GstPulseMixerCtrl*)(obj))
+typedef struct _GstPulseMixerCtrl GstPulseMixerCtrl;
+
+typedef enum
+{
+ GST_PULSEMIXER_UNKNOWN,
+ GST_PULSEMIXER_SINK,
+ GST_PULSEMIXER_SOURCE
+} GstPulseMixerType;
+
+struct _GstPulseMixerCtrl
+{
+ GObject *object;
+
+ GList *tracklist;
+
+ gchar *server, *device;
+
+ pa_threaded_mainloop *mainloop;
+ pa_context *context;
+
+ gchar *name, *description;
+ pa_channel_map channel_map;
+
+ pa_cvolume volume;
+ gboolean muted:1;
+
+ gboolean update_volume:1;
+ gboolean update_mute:1;
+
+ gboolean operation_success:1;
+
+ guint32 index;
+ GstPulseMixerType type;
+
+ GstMixerTrack *track;
+
+ pa_time_event *time_event;
+
+ int outstandig_queries;
+ int ignore_queries;
+
+};
+
+GstPulseMixerCtrl *gst_pulsemixer_ctrl_new (GObject *object, const gchar * server,
+ const gchar * device, GstPulseMixerType type);
+void gst_pulsemixer_ctrl_free (GstPulseMixerCtrl * mixer);
+
+const GList *gst_pulsemixer_ctrl_list_tracks (GstPulseMixerCtrl * mixer);
+
+void gst_pulsemixer_ctrl_set_volume (GstPulseMixerCtrl * mixer,
+ GstMixerTrack * track, gint * volumes);
+void gst_pulsemixer_ctrl_get_volume (GstPulseMixerCtrl * mixer,
+ GstMixerTrack * track, gint * volumes);
+void gst_pulsemixer_ctrl_set_mute (GstPulseMixerCtrl * mixer,
+ GstMixerTrack * track, gboolean mute);
+void gst_pulsemixer_ctrl_set_record (GstPulseMixerCtrl * mixer,
+ GstMixerTrack * track, gboolean record);
+GstMixerFlags gst_pulsemixer_ctrl_get_mixer_flags (GstPulseMixerCtrl * mixer);
+
+#define GST_IMPLEMENT_PULSEMIXER_CTRL_METHODS(Type, interface_as_function) \
+static const GList* \
+interface_as_function ## _list_tracks (GstMixer * mixer) \
+{ \
+ Type *this = (Type*) mixer; \
+ \
+ g_return_val_if_fail (this != NULL, NULL); \
+ g_return_val_if_fail (this->mixer != NULL, NULL); \
+ \
+ return gst_pulsemixer_ctrl_list_tracks (this->mixer); \
+} \
+static void \
+interface_as_function ## _set_volume (GstMixer * mixer, GstMixerTrack * track, \
+ gint * volumes) \
+{ \
+ Type *this = (Type*) mixer; \
+ \
+ g_return_if_fail (this != NULL); \
+ g_return_if_fail (this->mixer != NULL); \
+ \
+ gst_pulsemixer_ctrl_set_volume (this->mixer, track, volumes); \
+} \
+static void \
+interface_as_function ## _get_volume (GstMixer * mixer, GstMixerTrack * track, \
+ gint * volumes) \
+{ \
+ Type *this = (Type*) mixer; \
+ \
+ g_return_if_fail (this != NULL); \
+ g_return_if_fail (this->mixer != NULL); \
+ \
+ gst_pulsemixer_ctrl_get_volume (this->mixer, track, volumes); \
+} \
+static void \
+interface_as_function ## _set_record (GstMixer * mixer, GstMixerTrack * track, \
+ gboolean record) \
+{ \
+ Type *this = (Type*) mixer; \
+ \
+ g_return_if_fail (this != NULL); \
+ g_return_if_fail (this->mixer != NULL); \
+ \
+ gst_pulsemixer_ctrl_set_record (this->mixer, track, record); \
+} \
+static void \
+interface_as_function ## _set_mute (GstMixer * mixer, GstMixerTrack * track, \
+ gboolean mute) \
+{ \
+ Type *this = (Type*) mixer; \
+ \
+ g_return_if_fail (this != NULL); \
+ g_return_if_fail (this->mixer != NULL); \
+ \
+ gst_pulsemixer_ctrl_set_mute (this->mixer, track, mute); \
+} \
+static GstMixerFlags \
+interface_as_function ## _get_mixer_flags (GstMixer * mixer) \
+{ \
+ Type *this = (Type*) mixer; \
+ \
+ g_return_val_if_fail (this != NULL, GST_MIXER_FLAG_NONE); \
+ g_return_val_if_fail (this->mixer != NULL, GST_MIXER_FLAG_NONE); \
+ \
+ return gst_pulsemixer_ctrl_get_mixer_flags (this->mixer); \
+} \
+static void \
+interface_as_function ## _mixer_interface_init (GstMixerClass * klass) \
+{ \
+ GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; \
+ \
+ klass->list_tracks = interface_as_function ## _list_tracks; \
+ klass->set_volume = interface_as_function ## _set_volume; \
+ klass->get_volume = interface_as_function ## _get_volume; \
+ klass->set_mute = interface_as_function ## _set_mute; \
+ klass->set_record = interface_as_function ## _set_record; \
+ klass->get_mixer_flags = interface_as_function ## _get_mixer_flags; \
+}
+
+G_END_DECLS
+
+#endif
diff --git a/ext/pulse/pulsemixertrack.c b/ext/pulse/pulsemixertrack.c
new file mode 100644
index 0000000..981351c
--- /dev/null
+++ b/ext/pulse/pulsemixertrack.c
@@ -0,0 +1,67 @@
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+
+#include "pulsemixertrack.h"
+
+GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
+#define GST_CAT_DEFAULT pulse_debug
+
+G_DEFINE_TYPE (GstPulseMixerTrack, gst_pulsemixer_track, GST_TYPE_MIXER_TRACK);
+
+static void
+gst_pulsemixer_track_class_init (GstPulseMixerTrackClass * klass)
+{
+}
+
+static void
+gst_pulsemixer_track_init (GstPulseMixerTrack * track)
+{
+ track->control = NULL;
+}
+
+GstMixerTrack *
+gst_pulsemixer_track_new (GstPulseMixerCtrl * control)
+{
+ GstPulseMixerTrack *pulsetrack;
+ GstMixerTrack *track;
+
+ pulsetrack = g_object_new (GST_TYPE_PULSEMIXER_TRACK, NULL);
+ pulsetrack->control = control;
+
+ track = GST_MIXER_TRACK (pulsetrack);
+ track->label = g_strdup ("Master");
+ track->num_channels = control->channel_map.channels;
+ track->flags =
+ (control->type ==
+ GST_PULSEMIXER_SINK ? GST_MIXER_TRACK_OUTPUT | GST_MIXER_TRACK_MASTER :
+ GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_RECORD) | (control->muted ?
+ GST_MIXER_TRACK_MUTE : 0);
+ track->min_volume = PA_VOLUME_MUTED;
+ track->max_volume = PA_VOLUME_NORM;
+
+ return track;
+}
diff --git a/ext/pulse/pulsemixertrack.h b/ext/pulse/pulsemixertrack.h
new file mode 100644
index 0000000..5c958ed
--- /dev/null
+++ b/ext/pulse/pulsemixertrack.h
@@ -0,0 +1,60 @@
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifndef __GST_PULSEMIXERTRACK_H__
+#define __GST_PULSEMIXERTRACK_H__
+
+#include <gst/gst.h>
+
+#include "pulsemixerctrl.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PULSEMIXER_TRACK \
+ (gst_pulsemixer_track_get_type())
+#define GST_PULSEMIXER_TRACK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_PULSEMIXER_TRACK, GstPulseMixerTrack))
+#define GST_PULSEMIXER_TRACK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_PULSEMIXER_TRACK, GstPulseMixerTrackClass))
+#define GST_IS_PULSEMIXER_TRACK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_PULSEMIXER_TRACK))
+#define GST_IS_PULSEMIXER_TRACK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_PULSEMIXER_TRACK))
+
+
+typedef struct _GstPulseMixerTrack
+{
+ GstMixerTrack parent;
+ GstPulseMixerCtrl *control;
+} GstPulseMixerTrack;
+
+typedef struct _GstPulseMixerTrackClass
+{
+ GstMixerTrackClass parent;
+} GstPulseMixerTrackClass;
+
+GType gst_pulsemixer_track_get_type (void);
+
+GstMixerTrack *gst_pulsemixer_track_new (GstPulseMixerCtrl * control);
+
+G_END_DECLS
+
+#endif
diff --git a/ext/pulse/pulseprobe.c b/ext/pulse/pulseprobe.c
new file mode 100644
index 0000000..6ebbfb2
--- /dev/null
+++ b/ext/pulse/pulseprobe.c
@@ -0,0 +1,416 @@
+/*-*- Mode: C; c-basic-offset: 2 -*-*/
+
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pulseprobe.h"
+#include "pulseutil.h"
+
+GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
+#define GST_CAT_DEFAULT pulse_debug
+
+static void
+gst_pulseprobe_context_state_cb (pa_context * context, void *userdata)
+{
+ GstPulseProbe *c = (GstPulseProbe *) userdata;
+
+ /* Called from the background thread! */
+
+ switch (pa_context_get_state (context)) {
+ case PA_CONTEXT_READY:
+ case PA_CONTEXT_TERMINATED:
+ case PA_CONTEXT_FAILED:
+ pa_threaded_mainloop_signal (c->mainloop, 0);
+ break;
+
+ case PA_CONTEXT_UNCONNECTED:
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ break;
+ }
+}
+
+static void
+gst_pulseprobe_sink_info_cb (pa_context * context, const pa_sink_info * i,
+ int eol, void *userdata)
+{
+ GstPulseProbe *c = (GstPulseProbe *) userdata;
+
+ /* Called from the background thread! */
+
+ if (eol || !i) {
+ c->operation_success = eol > 0;
+ pa_threaded_mainloop_signal (c->mainloop, 0);
+ }
+
+ if (i)
+ c->devices = g_list_append (c->devices, g_strdup (i->name));
+
+}
+
+static void
+gst_pulseprobe_source_info_cb (pa_context * context, const pa_source_info * i,
+ int eol, void *userdata)
+{
+ GstPulseProbe *c = (GstPulseProbe *) userdata;
+
+ /* Called from the background thread! */
+
+ if (eol || !i) {
+ c->operation_success = eol > 0;
+ pa_threaded_mainloop_signal (c->mainloop, 0);
+ }
+
+ if (i)
+ c->devices = g_list_append (c->devices, g_strdup (i->name));
+}
+
+static void
+gst_pulseprobe_invalidate (GstPulseProbe * c)
+{
+ g_list_foreach (c->devices, (GFunc) g_free, NULL);
+ g_list_free (c->devices);
+ c->devices = NULL;
+ c->devices_valid = FALSE;
+}
+
+static gboolean
+gst_pulseprobe_open (GstPulseProbe * c)
+{
+ int e;
+ gchar *name;
+
+ g_assert (c);
+
+ GST_DEBUG_OBJECT (c->object, "probe open");
+
+ c->mainloop = pa_threaded_mainloop_new ();
+ if (!c->mainloop)
+ return FALSE;
+
+ e = pa_threaded_mainloop_start (c->mainloop);
+ if (e < 0)
+ return FALSE;
+
+ name = gst_pulse_client_name ();
+
+ pa_threaded_mainloop_lock (c->mainloop);
+
+ if (!(c->context =
+ pa_context_new (pa_threaded_mainloop_get_api (c->mainloop), name))) {
+ GST_WARNING_OBJECT (c->object, "Failed to create context");
+ goto unlock_and_fail;
+ }
+
+ pa_context_set_state_callback (c->context, gst_pulseprobe_context_state_cb,
+ c);
+
+ if (pa_context_connect (c->context, c->server, 0, NULL) < 0) {
+ GST_WARNING_OBJECT (c->object, "Failed to connect context: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+
+ for (;;) {
+ pa_context_state_t state;
+
+ state = pa_context_get_state (c->context);
+
+ if (!PA_CONTEXT_IS_GOOD (state)) {
+ GST_WARNING_OBJECT (c->object, "Failed to connect context: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+
+ if (state == PA_CONTEXT_READY)
+ break;
+
+ /* Wait until the context is ready */
+ pa_threaded_mainloop_wait (c->mainloop);
+ }
+
+ pa_threaded_mainloop_unlock (c->mainloop);
+ g_free (name);
+
+ gst_pulseprobe_invalidate (c);
+
+ return TRUE;
+
+unlock_and_fail:
+
+ if (c->mainloop)
+ pa_threaded_mainloop_unlock (c->mainloop);
+
+ g_free (name);
+
+ return FALSE;
+}
+
+static gboolean
+gst_pulseprobe_is_dead (GstPulseProbe * pulseprobe)
+{
+
+ if (!pulseprobe->context ||
+ !PA_CONTEXT_IS_GOOD (pa_context_get_state (pulseprobe->context))) {
+ const gchar *err_str =
+ pulseprobe->context ?
+ pa_strerror (pa_context_errno (pulseprobe->context)) : NULL;
+
+ GST_ELEMENT_ERROR ((pulseprobe), RESOURCE, FAILED,
+ ("Disconnected: %s", err_str), (NULL));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gst_pulseprobe_enumerate (GstPulseProbe * c)
+{
+ pa_operation *o = NULL;
+
+ GST_DEBUG_OBJECT (c->object, "probe enumerate");
+
+ pa_threaded_mainloop_lock (c->mainloop);
+
+ if (c->enumerate_sinks) {
+ /* Get sink info */
+
+ if (!(o =
+ pa_context_get_sink_info_list (c->context,
+ gst_pulseprobe_sink_info_cb, c))) {
+ GST_WARNING_OBJECT (c->object, "Failed to get sink info: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+
+ c->operation_success = FALSE;
+
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+
+ if (gst_pulseprobe_is_dead (c))
+ goto unlock_and_fail;
+
+ pa_threaded_mainloop_wait (c->mainloop);
+ }
+
+ if (!c->operation_success) {
+ GST_WARNING_OBJECT (c->object, "Failed to get sink info: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+
+ pa_operation_unref (o);
+ o = NULL;
+ }
+
+ if (c->enumerate_sources) {
+ /* Get source info */
+
+ if (!(o =
+ pa_context_get_source_info_list (c->context,
+ gst_pulseprobe_source_info_cb, c))) {
+ GST_WARNING_OBJECT (c->object, "Failed to get source info: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+
+ c->operation_success = FALSE;
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+
+ if (gst_pulseprobe_is_dead (c))
+ goto unlock_and_fail;
+
+ pa_threaded_mainloop_wait (c->mainloop);
+ }
+
+ if (!c->operation_success) {
+ GST_WARNING_OBJECT (c->object, "Failed to get sink info: %s",
+ pa_strerror (pa_context_errno (c->context)));
+ goto unlock_and_fail;
+ }
+
+ pa_operation_unref (o);
+ o = NULL;
+ }
+
+ c->devices_valid = TRUE;
+
+ pa_threaded_mainloop_unlock (c->mainloop);
+
+ return TRUE;
+
+unlock_and_fail:
+
+ if (o)
+ pa_operation_unref (o);
+
+ pa_threaded_mainloop_unlock (c->mainloop);
+
+ return FALSE;
+}
+
+static void
+gst_pulseprobe_close (GstPulseProbe * c)
+{
+ g_assert (c);
+
+ GST_DEBUG_OBJECT (c->object, "probe close");
+
+ if (c->mainloop)
+ pa_threaded_mainloop_stop (c->mainloop);
+
+ if (c->context) {
+ pa_context_disconnect (c->context);
+ pa_context_set_state_callback (c->context, NULL, NULL);
+ pa_context_unref (c->context);
+ c->context = NULL;
+ }
+
+ if (c->mainloop) {
+ pa_threaded_mainloop_free (c->mainloop);
+ c->mainloop = NULL;
+ }
+}
+
+GstPulseProbe *
+gst_pulseprobe_new (GObject * object, GObjectClass * klass,
+ guint prop_id, const gchar * server, gboolean sinks, gboolean sources)
+{
+ GstPulseProbe *c = NULL;
+
+ c = g_new (GstPulseProbe, 1);
+ c->object = object; /* We don't inc the ref counter here to avoid a ref loop */
+ c->server = g_strdup (server);
+ c->enumerate_sinks = sinks;
+ c->enumerate_sources = sources;
+
+ c->mainloop = NULL;
+ c->context = NULL;
+
+ c->prop_id = prop_id;
+ c->properties =
+ g_list_append (NULL, g_object_class_find_property (klass, "device"));
+
+ c->devices = NULL;
+ c->devices_valid = FALSE;
+
+ c->operation_success = FALSE;
+
+ return c;
+}
+
+void
+gst_pulseprobe_free (GstPulseProbe * c)
+{
+ g_assert (c);
+
+ gst_pulseprobe_close (c);
+
+ g_list_free (c->properties);
+ g_free (c->server);
+
+ g_list_foreach (c->devices, (GFunc) g_free, NULL);
+ g_list_free (c->devices);
+
+ g_free (c);
+}
+
+const GList *
+gst_pulseprobe_get_properties (GstPulseProbe * c)
+{
+ return c->properties;
+}
+
+gboolean
+gst_pulseprobe_needs_probe (GstPulseProbe * c, guint prop_id,
+ const GParamSpec * pspec)
+{
+
+ if (prop_id == c->prop_id)
+ return !c->devices_valid;
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (c->object, prop_id, pspec);
+ return FALSE;
+}
+
+void
+gst_pulseprobe_probe_property (GstPulseProbe * c, guint prop_id,
+ const GParamSpec * pspec)
+{
+
+ if (prop_id != c->prop_id) {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (c->object, prop_id, pspec);
+ return;
+ }
+
+ if (gst_pulseprobe_open (c)) {
+ gst_pulseprobe_enumerate (c);
+ gst_pulseprobe_close (c);
+ }
+}
+
+GValueArray *
+gst_pulseprobe_get_values (GstPulseProbe * c, guint prop_id,
+ const GParamSpec * pspec)
+{
+ GValueArray *array;
+ GValue value = {
+ 0
+ };
+ GList *item;
+
+ if (prop_id != c->prop_id) {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (c->object, prop_id, pspec);
+ return NULL;
+ }
+
+ if (!c->devices_valid)
+ return NULL;
+
+ array = g_value_array_new (g_list_length (c->devices));
+ g_value_init (&value, G_TYPE_STRING);
+ for (item = c->devices; item != NULL; item = item->next) {
+ GST_WARNING_OBJECT (c->object, "device found: %s",
+ (const gchar *) item->data);
+ g_value_set_string (&value, (const gchar *) item->data);
+ g_value_array_append (array, &value);
+ }
+ g_value_unset (&value);
+
+ return array;
+}
+
+void
+gst_pulseprobe_set_server (GstPulseProbe * c, const gchar * server)
+{
+ g_assert (c);
+
+ gst_pulseprobe_invalidate (c);
+
+ g_free (c->server);
+ c->server = g_strdup (server);
+}
diff --git a/ext/pulse/pulseprobe.h b/ext/pulse/pulseprobe.h
new file mode 100644
index 0000000..28cdbb8
--- /dev/null
+++ b/ext/pulse/pulseprobe.h
@@ -0,0 +1,127 @@
+/*-*- Mode: C; c-basic-offset: 2 -*-*/
+
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifndef __GST_PULSEPROBE_H__
+#define __GST_PULSEPROBE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#include <gst/interfaces/propertyprobe.h>
+#include <pulse/pulseaudio.h>
+#include <pulse/thread-mainloop.h>
+
+typedef struct _GstPulseProbe GstPulseProbe;
+
+struct _GstPulseProbe
+{
+ GObject *object;
+ gchar *server;
+
+ GList *devices;
+ gboolean devices_valid:1;
+
+ gboolean operation_success:1;
+
+ gboolean enumerate_sinks:1;
+ gboolean enumerate_sources:1;
+
+ pa_threaded_mainloop *mainloop;
+ pa_context *context;
+
+ GList *properties;
+ guint prop_id;
+};
+
+GstPulseProbe *gst_pulseprobe_new (GObject *object, GObjectClass * klass,
+ guint prop_id, const gchar * server, gboolean sinks, gboolean sources);
+void gst_pulseprobe_free (GstPulseProbe * probe);
+
+const GList *gst_pulseprobe_get_properties (GstPulseProbe * probe);
+
+gboolean gst_pulseprobe_needs_probe (GstPulseProbe * probe, guint prop_id,
+ const GParamSpec * pspec);
+void gst_pulseprobe_probe_property (GstPulseProbe * probe, guint prop_id,
+ const GParamSpec * pspec);
+GValueArray *gst_pulseprobe_get_values (GstPulseProbe * probe, guint prop_id,
+ const GParamSpec * pspec);
+
+void gst_pulseprobe_set_server (GstPulseProbe * c, const gchar * server);
+
+#define GST_IMPLEMENT_PULSEPROBE_METHODS(Type, interface_as_function) \
+static const GList* \
+interface_as_function ## _get_properties(GstPropertyProbe * probe) \
+{ \
+ Type *this = (Type*) probe; \
+ \
+ g_return_val_if_fail(this != NULL, NULL); \
+ g_return_val_if_fail(this->probe != NULL, NULL); \
+ \
+ return gst_pulseprobe_get_properties(this->probe); \
+} \
+static gboolean \
+interface_as_function ## _needs_probe(GstPropertyProbe *probe, guint prop_id, \
+ const GParamSpec *pspec) \
+{ \
+ Type *this = (Type*) probe; \
+ \
+ g_return_val_if_fail(this != NULL, FALSE); \
+ g_return_val_if_fail(this->probe != NULL, FALSE); \
+ \
+ return gst_pulseprobe_needs_probe(this->probe, prop_id, pspec); \
+} \
+static void \
+interface_as_function ## _probe_property(GstPropertyProbe *probe, \
+ guint prop_id, const GParamSpec *pspec) \
+{ \
+ Type *this = (Type*) probe; \
+ \
+ g_return_if_fail(this != NULL); \
+ g_return_if_fail(this->probe != NULL); \
+ \
+ gst_pulseprobe_probe_property(this->probe, prop_id, pspec); \
+} \
+static GValueArray* \
+interface_as_function ## _get_values(GstPropertyProbe *probe, guint prop_id, \
+ const GParamSpec *pspec) \
+{ \
+ Type *this = (Type*) probe; \
+ \
+ g_return_val_if_fail(this != NULL, NULL); \
+ g_return_val_if_fail(this->probe != NULL, NULL); \
+ \
+ return gst_pulseprobe_get_values(this->probe, prop_id, pspec); \
+} \
+static void \
+interface_as_function ## _property_probe_interface_init(GstPropertyProbeInterface *iface)\
+{ \
+ iface->get_properties = interface_as_function ## _get_properties; \
+ iface->needs_probe = interface_as_function ## _needs_probe; \
+ iface->probe_property = interface_as_function ## _probe_property; \
+ iface->get_values = interface_as_function ## _get_values; \
+}
+
+G_END_DECLS
+
+#endif
diff --git a/ext/pulse/pulsesink.c b/ext/pulse/pulsesink.c
new file mode 100644
index 0000000..11e9c89
--- /dev/null
+++ b/ext/pulse/pulsesink.c
@@ -0,0 +1,3024 @@
+/*-*- Mode: C; c-basic-offset: 2 -*-*/
+
+/* GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ * (c) 2009 Wim Taymans
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+/**
+ * SECTION:element-pulsesink
+ * @see_also: pulsesrc, pulsemixer
+ *
+ * This element outputs audio to a
+ * <ulink href="http://www.pulseaudio.org">PulseAudio sound server</ulink>.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! pulsesink
+ * ]| Play an Ogg/Vorbis file.
+ * |[
+ * gst-launch -v audiotestsrc ! audioconvert ! volume volume=0.4 ! pulsesink
+ * ]| Play a 440Hz sine wave.
+ * |[
+ * gst-launch -v audiotestsrc ! pulsesink stream-properties="props,media.title=test"
+ * ]| Play a sine wave and set a stream property. The property can be checked
+ * with "pactl list".
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include <gst/base/gstbasesink.h>
+#include <gst/gsttaglist.h>
+#include <gst/interfaces/streamvolume.h>
+#include <gst/gst-i18n-plugin.h>
+#include <gst/audio/gstaudioiec61937.h>
+
+#include <gst/pbutils/pbutils.h> /* only used for GST_PLUGINS_BASE_VERSION_* */
+
+#include <gst/glib-compat-private.h>
+
+#include "pulsesink.h"
+#include "pulseutil.h"
+
+GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
+#define GST_CAT_DEFAULT pulse_debug
+
+#define DEFAULT_SERVER NULL
+#define DEFAULT_DEVICE NULL
+#define DEFAULT_DEVICE_NAME NULL
+#define DEFAULT_VOLUME 1.0
+#define DEFAULT_MUTE FALSE
+#define MAX_VOLUME 10.0
+
+enum
+{
+ PROP_0,
+ PROP_SERVER,
+ PROP_DEVICE,
+ PROP_DEVICE_NAME,
+ PROP_VOLUME,
+ PROP_MUTE,
+ PROP_CLIENT,
+ PROP_STREAM_PROPERTIES,
+ PROP_LAST
+};
+
+#define GST_TYPE_PULSERING_BUFFER \
+ (gst_pulseringbuffer_get_type())
+#define GST_PULSERING_BUFFER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PULSERING_BUFFER,GstPulseRingBuffer))
+#define GST_PULSERING_BUFFER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PULSERING_BUFFER,GstPulseRingBufferClass))
+#define GST_PULSERING_BUFFER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PULSERING_BUFFER, GstPulseRingBufferClass))
+#define GST_PULSERING_BUFFER_CAST(obj) \
+ ((GstPulseRingBuffer *)obj)
+#define GST_IS_PULSERING_BUFFER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PULSERING_BUFFER))
+#define GST_IS_PULSERING_BUFFER_CLASS(klass)\
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PULSERING_BUFFER))
+
+typedef struct _GstPulseRingBuffer GstPulseRingBuffer;
+typedef struct _GstPulseRingBufferClass GstPulseRingBufferClass;
+
+typedef struct _GstPulseContext GstPulseContext;
+
+/* Store the PA contexts in a hash table to allow easy sharing among
+ * multiple instances of the sink. Keys are $context_name@$server_name
+ * (strings) and values should be GstPulseContext pointers.
+ */
+struct _GstPulseContext
+{
+ pa_context *context;
+ GSList *ring_buffers;
+};
+
+static GHashTable *gst_pulse_shared_contexts = NULL;
+
+/* use one static main-loop for all instances
+ * this is needed to make the context sharing work as the contexts are
+ * released when releasing their parent main-loop
+ */
+static pa_threaded_mainloop *mainloop = NULL;
+static guint mainloop_ref_ct = 0;
+
+/* lock for access to shared resources */
+static GMutex *pa_shared_resource_mutex = NULL;
+
+/* We keep a custom ringbuffer that is backed up by data allocated by
+ * pulseaudio. We must also overide the commit function to write into
+ * pulseaudio memory instead. */
+struct _GstPulseRingBuffer
+{
+ GstRingBuffer object;
+
+ gchar *context_name;
+ gchar *stream_name;
+
+ pa_context *context;
+ pa_stream *stream;
+
+#ifdef HAVE_PULSE_1_0
+ pa_format_info *format;
+ guint channels;
+ gboolean is_pcm;
+#else
+ pa_sample_spec sample_spec;
+#endif
+
+ void *m_data;
+ size_t m_towrite;
+ size_t m_writable;
+ gint64 m_offset;
+ gint64 m_lastoffset;
+
+ gboolean corked:1;
+ gboolean in_commit:1;
+ gboolean paused:1;
+};
+struct _GstPulseRingBufferClass
+{
+ GstRingBufferClass parent_class;
+};
+
+static GType gst_pulseringbuffer_get_type (void);
+static void gst_pulseringbuffer_finalize (GObject * object);
+
+static GstRingBufferClass *ring_parent_class = NULL;
+
+static gboolean gst_pulseringbuffer_open_device (GstRingBuffer * buf);
+static gboolean gst_pulseringbuffer_close_device (GstRingBuffer * buf);
+static gboolean gst_pulseringbuffer_acquire (GstRingBuffer * buf,
+ GstRingBufferSpec * spec);
+static gboolean gst_pulseringbuffer_release (GstRingBuffer * buf);
+static gboolean gst_pulseringbuffer_start (GstRingBuffer * buf);
+static gboolean gst_pulseringbuffer_pause (GstRingBuffer * buf);
+static gboolean gst_pulseringbuffer_stop (GstRingBuffer * buf);
+static void gst_pulseringbuffer_clear (GstRingBuffer * buf);
+static guint gst_pulseringbuffer_commit (GstRingBuffer * buf,
+ guint64 * sample, guchar * data, gint in_samples, gint out_samples,
+ gint * accum);
+
+G_DEFINE_TYPE (GstPulseRingBuffer, gst_pulseringbuffer, GST_TYPE_RING_BUFFER);
+
+static void
+gst_pulsesink_init_contexts (void)
+{
+ g_assert (pa_shared_resource_mutex == NULL);
+ pa_shared_resource_mutex = g_mutex_new ();
+ gst_pulse_shared_contexts = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+}
+
+static void
+gst_pulseringbuffer_class_init (GstPulseRingBufferClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstRingBufferClass *gstringbuffer_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstringbuffer_class = (GstRingBufferClass *) klass;
+
+ ring_parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->finalize = gst_pulseringbuffer_finalize;
+
+ gstringbuffer_class->open_device =
+ GST_DEBUG_FUNCPTR (gst_pulseringbuffer_open_device);
+ gstringbuffer_class->close_device =
+ GST_DEBUG_FUNCPTR (gst_pulseringbuffer_close_device);
+ gstringbuffer_class->acquire =
+ GST_DEBUG_FUNCPTR (gst_pulseringbuffer_acquire);
+ gstringbuffer_class->release =
+ GST_DEBUG_FUNCPTR (gst_pulseringbuffer_release);
+ gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_pulseringbuffer_start);
+ gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_pulseringbuffer_pause);
+ gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_pulseringbuffer_start);
+ gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_pulseringbuffer_stop);
+ gstringbuffer_class->clear_all =
+ GST_DEBUG_FUNCPTR (gst_pulseringbuffer_clear);
+
+ gstringbuffer_class->commit = GST_DEBUG_FUNCPTR (gst_pulseringbuffer_commit);
+}
+
+static void
+gst_pulseringbuffer_init (GstPulseRingBuffer * pbuf)
+{
+ pbuf->stream_name = NULL;
+ pbuf->context = NULL;
+ pbuf->stream = NULL;
+
+#ifdef HAVE_PULSE_1_0
+ pbuf->format = NULL;
+ pbuf->channels = 0;
+ pbuf->is_pcm = FALSE;
+#else
+ pa_sample_spec_init (&pbuf->sample_spec);
+#endif
+
+ pbuf->m_data = NULL;
+ pbuf->m_towrite = 0;
+ pbuf->m_writable = 0;
+ pbuf->m_offset = 0;
+ pbuf->m_lastoffset = 0;
+
+ pbuf->corked = TRUE;
+ pbuf->in_commit = FALSE;
+ pbuf->paused = FALSE;
+}
+
+static void
+gst_pulsering_destroy_stream (GstPulseRingBuffer * pbuf)
+{
+ if (pbuf->stream) {
+
+ if (pbuf->m_data) {
+ /* drop shm memory buffer */
+ pa_stream_cancel_write (pbuf->stream);
+
+ /* reset internal variables */
+ pbuf->m_data = NULL;
+ pbuf->m_towrite = 0;
+ pbuf->m_writable = 0;
+ pbuf->m_offset = 0;
+ pbuf->m_lastoffset = 0;
+ }
+#ifdef HAVE_PULSE_1_0
+ if (pbuf->format) {
+ pa_format_info_free (pbuf->format);
+ pbuf->format = NULL;
+ pbuf->channels = 0;
+ pbuf->is_pcm = FALSE;
+ }
+#endif
+
+ pa_stream_disconnect (pbuf->stream);
+
+ /* Make sure we don't get any further callbacks */
+ pa_stream_set_state_callback (pbuf->stream, NULL, NULL);
+ pa_stream_set_write_callback (pbuf->stream, NULL, NULL);
+ pa_stream_set_underflow_callback (pbuf->stream, NULL, NULL);
+ pa_stream_set_overflow_callback (pbuf->stream, NULL, NULL);
+
+ pa_stream_unref (pbuf->stream);
+ pbuf->stream = NULL;
+ }
+
+ g_free (pbuf->stream_name);
+ pbuf->stream_name = NULL;
+}
+
+static void
+gst_pulsering_destroy_context (GstPulseRingBuffer * pbuf)
+{
+ g_mutex_lock (pa_shared_resource_mutex);
+
+ GST_DEBUG_OBJECT (pbuf, "destroying ringbuffer %p", pbuf);
+
+ gst_pulsering_destroy_stream (pbuf);
+
+ if (pbuf->context) {
+ pa_context_unref (pbuf->context);
+ pbuf->context = NULL;
+ }
+
+ if (pbuf->context_name) {
+ GstPulseContext *pctx;
+
+ pctx = g_hash_table_lookup (gst_pulse_shared_contexts, pbuf->context_name);
+
+ GST_DEBUG_OBJECT (pbuf, "releasing context with name %s, pbuf=%p, pctx=%p",
+ pbuf->context_name, pbuf, pctx);
+
+ if (pctx) {
+ pctx->ring_buffers = g_slist_remove (pctx->ring_buffers, pbuf);
+ if (pctx->ring_buffers == NULL) {
+ GST_DEBUG_OBJECT (pbuf,
+ "destroying final context with name %s, pbuf=%p, pctx=%p",
+ pbuf->context_name, pbuf, pctx);
+
+ pa_context_disconnect (pctx->context);
+
+ /* Make sure we don't get any further callbacks */
+ pa_context_set_state_callback (pctx->context, NULL, NULL);
+ pa_context_set_subscribe_callback (pctx->context, NULL, NULL);
+
+ g_hash_table_remove (gst_pulse_shared_contexts, pbuf->context_name);
+
+ pa_context_unref (pctx->context);
+ g_slice_free (GstPulseContext, pctx);
+ }
+ }
+ g_free (pbuf->context_name);
+ pbuf->context_name = NULL;
+ }
+ g_mutex_unlock (pa_shared_resource_mutex);
+}
+
+static void
+gst_pulseringbuffer_finalize (GObject * object)
+{
+ GstPulseRingBuffer *ringbuffer;
+
+ ringbuffer = GST_PULSERING_BUFFER_CAST (object);
+
+ gst_pulsering_destroy_context (ringbuffer);
+ G_OBJECT_CLASS (ring_parent_class)->finalize (object);
+}
+
+
+#define CONTEXT_OK(c) ((c) && PA_CONTEXT_IS_GOOD (pa_context_get_state ((c))))
+#define STREAM_OK(s) ((s) && PA_STREAM_IS_GOOD (pa_stream_get_state ((s))))
+
+static gboolean
+gst_pulsering_is_dead (GstPulseSink * psink, GstPulseRingBuffer * pbuf,
+ gboolean check_stream)
+{
+ if (!CONTEXT_OK (pbuf->context))
+ goto error;
+
+ if (check_stream && !STREAM_OK (pbuf->stream))
+ goto error;
+
+ return FALSE;
+
+error:
+ {
+ const gchar *err_str =
+ pbuf->context ? pa_strerror (pa_context_errno (pbuf->context)) : NULL;
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED, ("Disconnected: %s",
+ err_str), (NULL));
+ return TRUE;
+ }
+}
+
+static void
+gst_pulsering_context_state_cb (pa_context * c, void *userdata)
+{
+ pa_context_state_t state;
+ pa_threaded_mainloop *mainloop = (pa_threaded_mainloop *) userdata;
+
+ state = pa_context_get_state (c);
+
+ GST_LOG ("got new context state %d", state);
+
+ switch (state) {
+ case PA_CONTEXT_READY:
+ case PA_CONTEXT_TERMINATED:
+ case PA_CONTEXT_FAILED:
+ GST_LOG ("signaling");
+ pa_threaded_mainloop_signal (mainloop, 0);
+ break;
+
+ case PA_CONTEXT_UNCONNECTED:
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ break;
+ }
+}
+
+static void
+gst_pulsering_context_subscribe_cb (pa_context * c,
+ pa_subscription_event_type_t t, uint32_t idx, void *userdata)
+{
+ GstPulseSink *psink;
+ GstPulseContext *pctx = (GstPulseContext *) userdata;
+ GSList *walk;
+
+ if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT | PA_SUBSCRIPTION_EVENT_CHANGE) &&
+ t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT | PA_SUBSCRIPTION_EVENT_NEW))
+ return;
+
+ for (walk = pctx->ring_buffers; walk; walk = g_slist_next (walk)) {
+ GstPulseRingBuffer *pbuf = (GstPulseRingBuffer *) walk->data;
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ GST_LOG_OBJECT (psink, "type %d, idx %u", t, idx);
+
+ if (!pbuf->stream)
+ continue;
+
+ if (idx != pa_stream_get_index (pbuf->stream))
+ continue;
+
+#ifdef HAVE_PULSE_1_0
+ if (psink->device && pbuf->is_pcm &&
+ !g_str_equal (psink->device,
+ pa_stream_get_device_name (pbuf->stream))) {
+ /* Underlying sink changed. And this is not a passthrough stream. Let's
+ * see if someone upstream wants to try to renegotiate. */
+ GstEvent *renego;
+
+ g_free (psink->device);
+ psink->device = g_strdup (pa_stream_get_device_name (pbuf->stream));
+
+ GST_INFO_OBJECT (psink, "emitting sink-changed");
+
+ renego = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+ gst_structure_new ("pulse-sink-changed", NULL));
+
+ if (!gst_pad_push_event (GST_BASE_SINK (psink)->sinkpad, renego))
+ GST_DEBUG_OBJECT (psink, "Emitted sink-changed - nobody was listening");
+ }
+#endif
+
+ /* Actually this event is also triggered when other properties of
+ * the stream change that are unrelated to the volume. However it is
+ * probably cheaper to signal the change here and check for the
+ * volume when the GObject property is read instead of querying it always. */
+
+ /* inform streaming thread to notify */
+ g_atomic_int_compare_and_exchange (&psink->notify, 0, 1);
+ }
+}
+
+/* will be called when the device should be opened. In this case we will connect
+ * to the server. We should not try to open any streams in this state. */
+static gboolean
+gst_pulseringbuffer_open_device (GstRingBuffer * buf)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+ GstPulseContext *pctx;
+ pa_mainloop_api *api;
+ gboolean need_unlock_shared;
+
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (buf));
+ pbuf = GST_PULSERING_BUFFER_CAST (buf);
+
+ g_assert (!pbuf->stream);
+ g_assert (psink->client_name);
+
+ if (psink->server)
+ pbuf->context_name = g_strdup_printf ("%s@%s", psink->client_name,
+ psink->server);
+ else
+ pbuf->context_name = g_strdup (psink->client_name);
+
+ pa_threaded_mainloop_lock (mainloop);
+
+ g_mutex_lock (pa_shared_resource_mutex);
+ need_unlock_shared = TRUE;
+
+ pctx = g_hash_table_lookup (gst_pulse_shared_contexts, pbuf->context_name);
+ if (pctx == NULL) {
+ pctx = g_slice_new0 (GstPulseContext);
+
+ /* get the mainloop api and create a context */
+ GST_INFO_OBJECT (psink, "new context with name %s, pbuf=%p, pctx=%p",
+ pbuf->context_name, pbuf, pctx);
+ api = pa_threaded_mainloop_get_api (mainloop);
+ if (!(pctx->context = pa_context_new (api, pbuf->context_name)))
+ goto create_failed;
+
+ pctx->ring_buffers = g_slist_prepend (pctx->ring_buffers, pbuf);
+ g_hash_table_insert (gst_pulse_shared_contexts,
+ g_strdup (pbuf->context_name), (gpointer) pctx);
+ /* register some essential callbacks */
+ pa_context_set_state_callback (pctx->context,
+ gst_pulsering_context_state_cb, mainloop);
+ pa_context_set_subscribe_callback (pctx->context,
+ gst_pulsering_context_subscribe_cb, pctx);
+
+ /* try to connect to the server and wait for completion, we don't want to
+ * autospawn a deamon */
+ GST_LOG_OBJECT (psink, "connect to server %s",
+ GST_STR_NULL (psink->server));
+ if (pa_context_connect (pctx->context, psink->server,
+ PA_CONTEXT_NOAUTOSPAWN, NULL) < 0)
+ goto connect_failed;
+ } else {
+ GST_INFO_OBJECT (psink,
+ "reusing shared context with name %s, pbuf=%p, pctx=%p",
+ pbuf->context_name, pbuf, pctx);
+ pctx->ring_buffers = g_slist_prepend (pctx->ring_buffers, pbuf);
+ }
+
+ g_mutex_unlock (pa_shared_resource_mutex);
+ need_unlock_shared = FALSE;
+
+ /* context created or shared okay */
+ pbuf->context = pa_context_ref (pctx->context);
+
+ for (;;) {
+ pa_context_state_t state;
+
+ state = pa_context_get_state (pbuf->context);
+
+ GST_LOG_OBJECT (psink, "context state is now %d", state);
+
+ if (!PA_CONTEXT_IS_GOOD (state))
+ goto connect_failed;
+
+ if (state == PA_CONTEXT_READY)
+ break;
+
+ /* Wait until the context is ready */
+ GST_LOG_OBJECT (psink, "waiting..");
+ pa_threaded_mainloop_wait (mainloop);
+ }
+
+ GST_LOG_OBJECT (psink, "opened the device");
+
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return TRUE;
+
+ /* ERRORS */
+unlock_and_fail:
+ {
+ if (need_unlock_shared)
+ g_mutex_unlock (pa_shared_resource_mutex);
+ gst_pulsering_destroy_context (pbuf);
+ pa_threaded_mainloop_unlock (mainloop);
+ return FALSE;
+ }
+create_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("Failed to create context"), (NULL));
+ g_slice_free (GstPulseContext, pctx);
+ goto unlock_and_fail;
+ }
+connect_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED, ("Failed to connect: %s",
+ pa_strerror (pa_context_errno (pctx->context))), (NULL));
+ goto unlock_and_fail;
+ }
+}
+
+/* close the device */
+static gboolean
+gst_pulseringbuffer_close_device (GstRingBuffer * buf)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (buf);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (buf));
+
+ GST_LOG_OBJECT (psink, "closing device");
+
+ pa_threaded_mainloop_lock (mainloop);
+ gst_pulsering_destroy_context (pbuf);
+ pa_threaded_mainloop_unlock (mainloop);
+
+ GST_LOG_OBJECT (psink, "closed device");
+
+ return TRUE;
+}
+
+static void
+gst_pulsering_stream_state_cb (pa_stream * s, void *userdata)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+ pa_stream_state_t state;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ state = pa_stream_get_state (s);
+ GST_LOG_OBJECT (psink, "got new stream state %d", state);
+
+ switch (state) {
+ case PA_STREAM_READY:
+ case PA_STREAM_FAILED:
+ case PA_STREAM_TERMINATED:
+ GST_LOG_OBJECT (psink, "signaling");
+ pa_threaded_mainloop_signal (mainloop, 0);
+ break;
+ case PA_STREAM_UNCONNECTED:
+ case PA_STREAM_CREATING:
+ break;
+ }
+}
+
+static void
+gst_pulsering_stream_request_cb (pa_stream * s, size_t length, void *userdata)
+{
+ GstPulseSink *psink;
+ GstRingBuffer *rbuf;
+ GstPulseRingBuffer *pbuf;
+
+ rbuf = GST_RING_BUFFER_CAST (userdata);
+ pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ GST_LOG_OBJECT (psink, "got request for length %" G_GSIZE_FORMAT, length);
+
+ if (pbuf->in_commit && (length >= rbuf->spec.segsize)) {
+ /* only signal when we are waiting in the commit thread
+ * and got request for atleast a segment */
+ pa_threaded_mainloop_signal (mainloop, 0);
+ }
+}
+
+static void
+gst_pulsering_stream_underflow_cb (pa_stream * s, void *userdata)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ GST_WARNING_OBJECT (psink, "Got underflow");
+}
+
+static void
+gst_pulsering_stream_overflow_cb (pa_stream * s, void *userdata)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ GST_WARNING_OBJECT (psink, "Got overflow");
+}
+
+static void
+gst_pulsering_stream_latency_cb (pa_stream * s, void *userdata)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+ const pa_timing_info *info;
+ pa_usec_t sink_usec;
+
+ info = pa_stream_get_timing_info (s);
+
+ pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ if (!info) {
+ GST_LOG_OBJECT (psink, "latency update (information unknown)");
+ return;
+ }
+ sink_usec = info->configured_sink_usec;
+
+ GST_LOG_OBJECT (psink,
+ "latency_update, %" G_GUINT64_FORMAT ", %d:%" G_GINT64_FORMAT ", %d:%"
+ G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT,
+ GST_TIMEVAL_TO_TIME (info->timestamp), info->write_index_corrupt,
+ info->write_index, info->read_index_corrupt, info->read_index,
+ info->sink_usec, sink_usec);
+}
+
+static void
+gst_pulsering_stream_suspended_cb (pa_stream * p, void *userdata)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ if (pa_stream_is_suspended (p))
+ GST_DEBUG_OBJECT (psink, "stream suspended");
+ else
+ GST_DEBUG_OBJECT (psink, "stream resumed");
+}
+
+static void
+gst_pulsering_stream_started_cb (pa_stream * p, void *userdata)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ GST_DEBUG_OBJECT (psink, "stream started");
+}
+
+static void
+gst_pulsering_stream_event_cb (pa_stream * p, const char *name,
+ pa_proplist * pl, void *userdata)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ if (!strcmp (name, PA_STREAM_EVENT_REQUEST_CORK)) {
+ /* the stream wants to PAUSE, post a message for the application. */
+ GST_DEBUG_OBJECT (psink, "got request for CORK");
+ gst_element_post_message (GST_ELEMENT_CAST (psink),
+ gst_message_new_request_state (GST_OBJECT_CAST (psink),
+ GST_STATE_PAUSED));
+
+ } else if (!strcmp (name, PA_STREAM_EVENT_REQUEST_UNCORK)) {
+ GST_DEBUG_OBJECT (psink, "got request for UNCORK");
+ gst_element_post_message (GST_ELEMENT_CAST (psink),
+ gst_message_new_request_state (GST_OBJECT_CAST (psink),
+ GST_STATE_PLAYING));
+#ifdef HAVE_PULSE_1_0
+ } else if (!strcmp (name, PA_STREAM_EVENT_FORMAT_LOST)) {
+ GstEvent *renego;
+
+ if (g_atomic_int_get (&psink->format_lost)) {
+ /* Duplicate event before we're done reconfiguring, discard */
+ return;
+ }
+
+ GST_DEBUG_OBJECT (psink, "got FORMAT LOST");
+ g_atomic_int_set (&psink->format_lost, 1);
+ psink->format_lost_time = g_ascii_strtoull (pa_proplist_gets (pl,
+ "stream-time"), NULL, 0) * 1000;
+
+ g_free (psink->device);
+ psink->device = g_strdup (pa_proplist_gets (pl, "device"));
+
+ renego = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+ gst_structure_new ("pulse-format-lost", NULL));
+
+ if (!gst_pad_push_event (GST_BASE_SINK (psink)->sinkpad, renego)) {
+ /* Nobody handled the format change - emit an error */
+ GST_ELEMENT_ERROR (psink, STREAM, FORMAT, ("Sink format changed"),
+ ("Sink format changed"));
+ }
+#endif
+ } else {
+ GST_DEBUG_OBJECT (psink, "got unknown event %s", name);
+ }
+}
+
+/* Called with the mainloop locked */
+static gboolean
+gst_pulsering_wait_for_stream_ready (GstPulseSink * psink, pa_stream * stream)
+{
+ pa_stream_state_t state;
+
+ for (;;) {
+ state = pa_stream_get_state (stream);
+
+ GST_LOG_OBJECT (psink, "stream state is now %d", state);
+
+ if (!PA_STREAM_IS_GOOD (state))
+ return FALSE;
+
+ if (state == PA_STREAM_READY)
+ return TRUE;
+
+ /* Wait until the stream is ready */
+ pa_threaded_mainloop_wait (mainloop);
+ }
+}
+
+
+/* This method should create a new stream of the given @spec. No playback should
+ * start yet so we start in the corked state. */
+static gboolean
+gst_pulseringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+ pa_buffer_attr wanted;
+ const pa_buffer_attr *actual;
+ pa_channel_map channel_map;
+ pa_operation *o = NULL;
+#ifdef HAVE_PULSE_0_9_20
+ pa_cvolume v;
+#endif
+ pa_cvolume *pv = NULL;
+ pa_stream_flags_t flags;
+ const gchar *name;
+ GstAudioClock *clock;
+#ifdef HAVE_PULSE_1_0
+ pa_format_info *formats[1];
+#ifndef GST_DISABLE_GST_DEBUG
+ gchar print_buf[PA_FORMAT_INFO_SNPRINT_MAX];
+#endif
+#endif
+
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (buf));
+ pbuf = GST_PULSERING_BUFFER_CAST (buf);
+
+ GST_LOG_OBJECT (psink, "creating sample spec");
+ /* convert the gstreamer sample spec to the pulseaudio format */
+#ifdef HAVE_PULSE_1_0
+ if (!gst_pulse_fill_format_info (spec, &pbuf->format, &pbuf->channels))
+ goto invalid_spec;
+ pbuf->is_pcm = pa_format_info_is_pcm (pbuf->format);
+#else
+ if (!gst_pulse_fill_sample_spec (spec, &pbuf->sample_spec))
+ goto invalid_spec;
+#endif
+
+ pa_threaded_mainloop_lock (mainloop);
+
+ /* we need a context and a no stream */
+ g_assert (pbuf->context);
+ g_assert (!pbuf->stream);
+
+ /* enable event notifications */
+ GST_LOG_OBJECT (psink, "subscribing to context events");
+ if (!(o = pa_context_subscribe (pbuf->context,
+ PA_SUBSCRIPTION_MASK_SINK_INPUT, NULL, NULL)))
+ goto subscribe_failed;
+
+ pa_operation_unref (o);
+
+ /* initialize the channel map */
+#ifdef HAVE_PULSE_1_0
+ if (pbuf->is_pcm && gst_pulse_gst_to_channel_map (&channel_map, spec))
+ pa_format_info_set_channel_map (pbuf->format, &channel_map);
+#else
+ gst_pulse_gst_to_channel_map (&channel_map, spec);
+#endif
+
+ /* find a good name for the stream */
+ if (psink->stream_name)
+ name = psink->stream_name;
+ else
+ name = "Playback Stream";
+
+ /* create a stream */
+#ifdef HAVE_PULSE_1_0
+ formats[0] = pbuf->format;
+ if (!(pbuf->stream = pa_stream_new_extended (pbuf->context, name, formats, 1,
+ psink->proplist)))
+ goto stream_failed;
+#else
+ GST_LOG_OBJECT (psink, "creating stream with name %s", name);
+ if (!(pbuf->stream = pa_stream_new_with_proplist (pbuf->context, name,
+ &pbuf->sample_spec, &channel_map, psink->proplist)))
+ goto stream_failed;
+#endif
+
+ /* install essential callbacks */
+ pa_stream_set_state_callback (pbuf->stream,
+ gst_pulsering_stream_state_cb, pbuf);
+ pa_stream_set_write_callback (pbuf->stream,
+ gst_pulsering_stream_request_cb, pbuf);
+ pa_stream_set_underflow_callback (pbuf->stream,
+ gst_pulsering_stream_underflow_cb, pbuf);
+ pa_stream_set_overflow_callback (pbuf->stream,
+ gst_pulsering_stream_overflow_cb, pbuf);
+ pa_stream_set_latency_update_callback (pbuf->stream,
+ gst_pulsering_stream_latency_cb, pbuf);
+ pa_stream_set_suspended_callback (pbuf->stream,
+ gst_pulsering_stream_suspended_cb, pbuf);
+ pa_stream_set_started_callback (pbuf->stream,
+ gst_pulsering_stream_started_cb, pbuf);
+ pa_stream_set_event_callback (pbuf->stream,
+ gst_pulsering_stream_event_cb, pbuf);
+
+ /* buffering requirements. When setting prebuf to 0, the stream will not pause
+ * when we cause an underrun, which causes time to continue. */
+ memset (&wanted, 0, sizeof (wanted));
+ wanted.tlength = spec->segtotal * spec->segsize;
+ wanted.maxlength = -1;
+ wanted.prebuf = 0;
+ wanted.minreq = spec->segsize;
+
+ GST_INFO_OBJECT (psink, "tlength: %d", wanted.tlength);
+ GST_INFO_OBJECT (psink, "maxlength: %d", wanted.maxlength);
+ GST_INFO_OBJECT (psink, "prebuf: %d", wanted.prebuf);
+ GST_INFO_OBJECT (psink, "minreq: %d", wanted.minreq);
+
+#ifdef HAVE_PULSE_0_9_20
+ /* configure volume when we changed it, else we leave the default */
+ if (psink->volume_set) {
+ GST_LOG_OBJECT (psink, "have volume of %f", psink->volume);
+ pv = &v;
+#ifdef HAVE_PULSE_1_0
+ if (pbuf->is_pcm)
+ gst_pulse_cvolume_from_linear (pv, pbuf->channels, psink->volume);
+ else {
+ GST_DEBUG_OBJECT (psink, "passthrough stream, not setting volume");
+ pv = NULL;
+ }
+#else
+ gst_pulse_cvolume_from_linear (pv, pbuf->sample_spec.channels,
+ psink->volume);
+#endif
+ } else {
+ pv = NULL;
+ }
+#endif
+
+ /* construct the flags */
+ flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
+ PA_STREAM_ADJUST_LATENCY | PA_STREAM_START_CORKED;
+
+ if (psink->mute_set && psink->mute)
+ flags |= PA_STREAM_START_MUTED;
+
+ /* we always start corked (see flags above) */
+ pbuf->corked = TRUE;
+
+ /* try to connect now */
+ GST_LOG_OBJECT (psink, "connect for playback to device %s",
+ GST_STR_NULL (psink->device));
+ if (pa_stream_connect_playback (pbuf->stream, psink->device,
+ &wanted, flags, pv, NULL) < 0)
+ goto connect_failed;
+
+ /* our clock will now start from 0 again */
+ clock = GST_AUDIO_CLOCK (GST_BASE_AUDIO_SINK (psink)->provided_clock);
+ gst_audio_clock_reset (clock, 0);
+
+ if (!gst_pulsering_wait_for_stream_ready (psink, pbuf->stream))
+ goto connect_failed;
+
+#ifdef HAVE_PULSE_1_0
+ g_free (psink->device);
+ psink->device = g_strdup (pa_stream_get_device_name (pbuf->stream));
+
+#ifndef GST_DISABLE_GST_DEBUG
+ pa_format_info_snprint (print_buf, sizeof (print_buf),
+ pa_stream_get_format_info (pbuf->stream));
+ GST_INFO_OBJECT (psink, "negotiated to: %s", print_buf);
+#endif
+#endif
+
+ /* After we passed the volume off of to PA we never want to set it
+ again, since it is PA's job to save/restore volumes. */
+ psink->volume_set = psink->mute_set = FALSE;
+
+ GST_LOG_OBJECT (psink, "stream is acquired now");
+
+ /* get the actual buffering properties now */
+ actual = pa_stream_get_buffer_attr (pbuf->stream);
+
+ GST_INFO_OBJECT (psink, "tlength: %d (wanted: %d)", actual->tlength,
+ wanted.tlength);
+ GST_INFO_OBJECT (psink, "maxlength: %d", actual->maxlength);
+ GST_INFO_OBJECT (psink, "prebuf: %d", actual->prebuf);
+ GST_INFO_OBJECT (psink, "minreq: %d (wanted %d)", actual->minreq,
+ wanted.minreq);
+
+ spec->segsize = actual->minreq;
+ spec->segtotal = actual->tlength / spec->segsize;
+
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return TRUE;
+
+ /* ERRORS */
+unlock_and_fail:
+ {
+ gst_pulsering_destroy_stream (pbuf);
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return FALSE;
+ }
+invalid_spec:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, SETTINGS,
+ ("Invalid sample specification."), (NULL));
+ return FALSE;
+ }
+subscribe_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_context_subscribe() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock_and_fail;
+ }
+stream_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("Failed to create stream: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock_and_fail;
+ }
+connect_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("Failed to connect stream: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock_and_fail;
+ }
+}
+
+/* free the stream that we acquired before */
+static gboolean
+gst_pulseringbuffer_release (GstRingBuffer * buf)
+{
+ GstPulseRingBuffer *pbuf;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (buf);
+
+ pa_threaded_mainloop_lock (mainloop);
+ gst_pulsering_destroy_stream (pbuf);
+ pa_threaded_mainloop_unlock (mainloop);
+
+#ifdef HAVE_PULSE_1_0
+ {
+ GstPulseSink *psink;
+
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+ g_atomic_int_set (&psink->format_lost, FALSE);
+ psink->format_lost_time = GST_CLOCK_TIME_NONE;
+ }
+#endif
+
+ return TRUE;
+}
+
+static void
+gst_pulsering_success_cb (pa_stream * s, int success, void *userdata)
+{
+ pa_threaded_mainloop_signal (mainloop, 0);
+}
+
+/* update the corked state of a stream, must be called with the mainloop
+ * lock */
+static gboolean
+gst_pulsering_set_corked (GstPulseRingBuffer * pbuf, gboolean corked,
+ gboolean wait)
+{
+ pa_operation *o = NULL;
+ GstPulseSink *psink;
+ gboolean res = FALSE;
+
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+#ifdef HAVE_PULSE_1_0
+ if (g_atomic_int_get (&psink->format_lost)) {
+ /* Sink format changed, stream's gone so fake being paused */
+ return TRUE;
+ }
+#endif
+
+ GST_DEBUG_OBJECT (psink, "setting corked state to %d", corked);
+ if (pbuf->corked != corked) {
+ if (!(o = pa_stream_cork (pbuf->stream, corked,
+ gst_pulsering_success_cb, pbuf)))
+ goto cork_failed;
+
+ while (wait && pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+ pa_threaded_mainloop_wait (mainloop);
+ if (gst_pulsering_is_dead (psink, pbuf, TRUE))
+ goto server_dead;
+ }
+ pbuf->corked = corked;
+ } else {
+ GST_DEBUG_OBJECT (psink, "skipping, already in requested state");
+ }
+ res = TRUE;
+
+cleanup:
+ if (o)
+ pa_operation_unref (o);
+
+ return res;
+
+ /* ERRORS */
+server_dead:
+ {
+ GST_DEBUG_OBJECT (psink, "the server is dead");
+ goto cleanup;
+ }
+cork_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_stream_cork() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto cleanup;
+ }
+}
+
+static void
+gst_pulseringbuffer_clear (GstRingBuffer * buf)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+ pa_operation *o = NULL;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (buf);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ pa_threaded_mainloop_lock (mainloop);
+ GST_DEBUG_OBJECT (psink, "clearing");
+ if (pbuf->stream) {
+ /* don't wait for the flush to complete */
+ if ((o = pa_stream_flush (pbuf->stream, NULL, pbuf)))
+ pa_operation_unref (o);
+ }
+ pa_threaded_mainloop_unlock (mainloop);
+}
+
+/* called from pulse with the mainloop lock */
+static void
+mainloop_enter_defer_cb (pa_mainloop_api * api, void *userdata)
+{
+ GstPulseSink *pulsesink = GST_PULSESINK (userdata);
+ GstMessage *message;
+ GValue val = { 0 };
+
+ g_value_init (&val, G_TYPE_POINTER);
+ g_value_set_pointer (&val, g_thread_self ());
+
+ GST_DEBUG_OBJECT (pulsesink, "posting ENTER stream status");
+ message = gst_message_new_stream_status (GST_OBJECT (pulsesink),
+ GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT (pulsesink));
+ gst_message_set_stream_status_object (message, &val);
+
+ gst_element_post_message (GST_ELEMENT (pulsesink), message);
+
+ g_return_if_fail (pulsesink->defer_pending);
+ pulsesink->defer_pending--;
+ pa_threaded_mainloop_signal (mainloop, 0);
+}
+
+/* start/resume playback ASAP, we don't uncork here but in the commit method */
+static gboolean
+gst_pulseringbuffer_start (GstRingBuffer * buf)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (buf);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ pa_threaded_mainloop_lock (mainloop);
+
+ GST_DEBUG_OBJECT (psink, "scheduling stream status");
+ psink->defer_pending++;
+ pa_mainloop_api_once (pa_threaded_mainloop_get_api (mainloop),
+ mainloop_enter_defer_cb, psink);
+
+ GST_DEBUG_OBJECT (psink, "starting");
+ pbuf->paused = FALSE;
+
+ /* EOS needs running clock */
+ if (GST_BASE_SINK_CAST (psink)->eos ||
+ g_atomic_int_get (&GST_BASE_AUDIO_SINK (psink)->abidata.
+ ABI.eos_rendering))
+ gst_pulsering_set_corked (pbuf, FALSE, FALSE);
+
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return TRUE;
+}
+
+/* pause/stop playback ASAP */
+static gboolean
+gst_pulseringbuffer_pause (GstRingBuffer * buf)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+ gboolean res;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (buf);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ pa_threaded_mainloop_lock (mainloop);
+ GST_DEBUG_OBJECT (psink, "pausing and corking");
+ /* make sure the commit method stops writing */
+ pbuf->paused = TRUE;
+ res = gst_pulsering_set_corked (pbuf, TRUE, TRUE);
+ if (pbuf->in_commit) {
+ /* we are waiting in a commit, signal */
+ GST_DEBUG_OBJECT (psink, "signal commit");
+ pa_threaded_mainloop_signal (mainloop, 0);
+ }
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return res;
+}
+
+/* called from pulse with the mainloop lock */
+static void
+mainloop_leave_defer_cb (pa_mainloop_api * api, void *userdata)
+{
+ GstPulseSink *pulsesink = GST_PULSESINK (userdata);
+ GstMessage *message;
+ GValue val = { 0 };
+
+ g_value_init (&val, G_TYPE_POINTER);
+ g_value_set_pointer (&val, g_thread_self ());
+
+ GST_DEBUG_OBJECT (pulsesink, "posting LEAVE stream status");
+ message = gst_message_new_stream_status (GST_OBJECT (pulsesink),
+ GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT (pulsesink));
+ gst_message_set_stream_status_object (message, &val);
+ gst_element_post_message (GST_ELEMENT (pulsesink), message);
+
+ g_return_if_fail (pulsesink->defer_pending);
+ pulsesink->defer_pending--;
+ pa_threaded_mainloop_signal (mainloop, 0);
+}
+
+/* stop playback, we flush everything. */
+static gboolean
+gst_pulseringbuffer_stop (GstRingBuffer * buf)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+ gboolean res = FALSE;
+ pa_operation *o = NULL;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (buf);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ pa_threaded_mainloop_lock (mainloop);
+
+ pbuf->paused = TRUE;
+ res = gst_pulsering_set_corked (pbuf, TRUE, TRUE);
+
+ /* Inform anyone waiting in _commit() call that it shall wakeup */
+ if (pbuf->in_commit) {
+ GST_DEBUG_OBJECT (psink, "signal commit thread");
+ pa_threaded_mainloop_signal (mainloop, 0);
+ }
+#ifdef HAVE_PULSE_1_0
+ if (g_atomic_int_get (&psink->format_lost)) {
+ /* Don't try to flush, the stream's probably gone by now */
+ res = TRUE;
+ goto cleanup;
+ }
+#endif
+
+ /* then try to flush, it's not fatal when this fails */
+ GST_DEBUG_OBJECT (psink, "flushing");
+ if ((o = pa_stream_flush (pbuf->stream, gst_pulsering_success_cb, pbuf))) {
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+ GST_DEBUG_OBJECT (psink, "wait for completion");
+ pa_threaded_mainloop_wait (mainloop);
+ if (gst_pulsering_is_dead (psink, pbuf, TRUE))
+ goto server_dead;
+ }
+ GST_DEBUG_OBJECT (psink, "flush completed");
+ }
+ res = TRUE;
+
+cleanup:
+ if (o) {
+ pa_operation_cancel (o);
+ pa_operation_unref (o);
+ }
+
+ GST_DEBUG_OBJECT (psink, "scheduling stream status");
+ psink->defer_pending++;
+ pa_mainloop_api_once (pa_threaded_mainloop_get_api (mainloop),
+ mainloop_leave_defer_cb, psink);
+
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return res;
+
+ /* ERRORS */
+server_dead:
+ {
+ GST_DEBUG_OBJECT (psink, "the server is dead");
+ goto cleanup;
+ }
+}
+
+/* in_samples >= out_samples, rate > 1.0 */
+#define FWD_UP_SAMPLES(s,se,d,de) \
+G_STMT_START { \
+ guint8 *sb = s, *db = d; \
+ while (s <= se && d < de) { \
+ memcpy (d, s, bps); \
+ s += bps; \
+ *accum += outr; \
+ if ((*accum << 1) >= inr) { \
+ *accum -= inr; \
+ d += bps; \
+ } \
+ } \
+ in_samples -= (s - sb)/bps; \
+ out_samples -= (d - db)/bps; \
+ GST_DEBUG ("fwd_up end %d/%d",*accum,*toprocess); \
+} G_STMT_END
+
+/* out_samples > in_samples, for rates smaller than 1.0 */
+#define FWD_DOWN_SAMPLES(s,se,d,de) \
+G_STMT_START { \
+ guint8 *sb = s, *db = d; \
+ while (s <= se && d < de) { \
+ memcpy (d, s, bps); \
+ d += bps; \
+ *accum += inr; \
+ if ((*accum << 1) >= outr) { \
+ *accum -= outr; \
+ s += bps; \
+ } \
+ } \
+ in_samples -= (s - sb)/bps; \
+ out_samples -= (d - db)/bps; \
+ GST_DEBUG ("fwd_down end %d/%d",*accum,*toprocess); \
+} G_STMT_END
+
+#define REV_UP_SAMPLES(s,se,d,de) \
+G_STMT_START { \
+ guint8 *sb = se, *db = d; \
+ while (s <= se && d < de) { \
+ memcpy (d, se, bps); \
+ se -= bps; \
+ *accum += outr; \
+ while (d < de && (*accum << 1) >= inr) { \
+ *accum -= inr; \
+ d += bps; \
+ } \
+ } \
+ in_samples -= (sb - se)/bps; \
+ out_samples -= (d - db)/bps; \
+ GST_DEBUG ("rev_up end %d/%d",*accum,*toprocess); \
+} G_STMT_END
+
+#define REV_DOWN_SAMPLES(s,se,d,de) \
+G_STMT_START { \
+ guint8 *sb = se, *db = d; \
+ while (s <= se && d < de) { \
+ memcpy (d, se, bps); \
+ d += bps; \
+ *accum += inr; \
+ while (s <= se && (*accum << 1) >= outr) { \
+ *accum -= outr; \
+ se -= bps; \
+ } \
+ } \
+ in_samples -= (sb - se)/bps; \
+ out_samples -= (d - db)/bps; \
+ GST_DEBUG ("rev_down end %d/%d",*accum,*toprocess); \
+} G_STMT_END
+
+/* our custom commit function because we write into the buffer of pulseaudio
+ * instead of keeping our own buffer */
+static guint
+gst_pulseringbuffer_commit (GstRingBuffer * buf, guint64 * sample,
+ guchar * data, gint in_samples, gint out_samples, gint * accum)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+ guint result;
+ guint8 *data_end;
+ gboolean reverse;
+ gint *toprocess;
+ gint inr, outr, bps;
+ gint64 offset;
+ guint bufsize;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (buf);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ /* FIXME post message rather than using a signal (as mixer interface) */
+ if (g_atomic_int_compare_and_exchange (&psink->notify, 1, 0)) {
+ g_object_notify (G_OBJECT (psink), "volume");
+ g_object_notify (G_OBJECT (psink), "mute");
+ }
+
+ /* make sure the ringbuffer is started */
+ if (G_UNLIKELY (g_atomic_int_get (&buf->state) !=
+ GST_RING_BUFFER_STATE_STARTED)) {
+ /* see if we are allowed to start it */
+ if (G_UNLIKELY (g_atomic_int_get (&buf->abidata.ABI.may_start) == FALSE))
+ goto no_start;
+
+ GST_DEBUG_OBJECT (buf, "start!");
+ if (!gst_ring_buffer_start (buf))
+ goto start_failed;
+ }
+
+ pa_threaded_mainloop_lock (mainloop);
+
+ GST_DEBUG_OBJECT (psink, "entering commit");
+ pbuf->in_commit = TRUE;
+
+ bps = buf->spec.bytes_per_sample;
+ bufsize = buf->spec.segsize * buf->spec.segtotal;
+
+ /* our toy resampler for trick modes */
+ reverse = out_samples < 0;
+ out_samples = ABS (out_samples);
+
+ if (in_samples >= out_samples)
+ toprocess = &in_samples;
+ else
+ toprocess = &out_samples;
+
+ inr = in_samples - 1;
+ outr = out_samples - 1;
+
+ GST_DEBUG_OBJECT (psink, "in %d, out %d", inr, outr);
+
+ /* data_end points to the last sample we have to write, not past it. This is
+ * needed to properly handle reverse playback: it points to the last sample. */
+ data_end = data + (bps * inr);
+
+#ifdef HAVE_PULSE_1_0
+ if (g_atomic_int_get (&psink->format_lost)) {
+ /* Sink format changed, drop the data and hope upstream renegotiates */
+ goto fake_done;
+ }
+#endif
+
+ if (pbuf->paused)
+ goto was_paused;
+
+ /* offset is in bytes */
+ offset = *sample * bps;
+
+ while (*toprocess > 0) {
+ size_t avail;
+ guint towrite;
+
+ GST_LOG_OBJECT (psink,
+ "need to write %d samples at offset %" G_GINT64_FORMAT, *toprocess,
+ offset);
+
+ if (offset != pbuf->m_lastoffset)
+ GST_LOG_OBJECT (psink, "discontinuity, offset is %" G_GINT64_FORMAT ", "
+ "last offset was %" G_GINT64_FORMAT, offset, pbuf->m_lastoffset);
+
+ towrite = out_samples * bps;
+
+ /* Wait for at least segsize bytes to become available */
+ if (towrite > buf->spec.segsize)
+ towrite = buf->spec.segsize;
+
+ if ((pbuf->m_writable < towrite) || (offset != pbuf->m_lastoffset)) {
+ /* if no room left or discontinuity in offset,
+ we need to flush data and get a new buffer */
+
+ /* flush the buffer if possible */
+ if ((pbuf->m_data != NULL) && (pbuf->m_towrite > 0)) {
+
+ GST_LOG_OBJECT (psink,
+ "flushing %u samples at offset %" G_GINT64_FORMAT,
+ (guint) pbuf->m_towrite / bps, pbuf->m_offset);
+
+ if (pa_stream_write (pbuf->stream, (uint8_t *) pbuf->m_data,
+ pbuf->m_towrite, NULL, pbuf->m_offset, PA_SEEK_ABSOLUTE) < 0) {
+ goto write_failed;
+ }
+ }
+ pbuf->m_towrite = 0;
+ pbuf->m_offset = offset; /* keep track of current offset */
+
+ /* get a buffer to write in for now on */
+ for (;;) {
+ pbuf->m_writable = pa_stream_writable_size (pbuf->stream);
+
+#ifdef HAVE_PULSE_1_0
+ if (g_atomic_int_get (&psink->format_lost)) {
+ /* Sink format changed, give up and hope upstream renegotiates */
+ goto fake_done;
+ }
+#endif
+
+ if (pbuf->m_writable == (size_t) - 1)
+ goto writable_size_failed;
+
+ pbuf->m_writable /= bps;
+ pbuf->m_writable *= bps; /* handle only complete samples */
+
+ if (pbuf->m_writable >= towrite)
+ break;
+
+ /* see if we need to uncork because we have no free space */
+ if (pbuf->corked) {
+ if (!gst_pulsering_set_corked (pbuf, FALSE, FALSE))
+ goto uncork_failed;
+ }
+
+ /* we can't write segsize bytes, wait a bit */
+ GST_LOG_OBJECT (psink, "waiting for free space");
+ pa_threaded_mainloop_wait (mainloop);
+
+ if (pbuf->paused)
+ goto was_paused;
+ }
+
+ /* Recalculate what we can write in the next chunk */
+ towrite = out_samples * bps;
+ if (pbuf->m_writable > towrite)
+ pbuf->m_writable = towrite;
+
+ GST_LOG_OBJECT (psink, "requesting %" G_GSIZE_FORMAT " bytes of "
+ "shared memory", pbuf->m_writable);
+
+ if (pa_stream_begin_write (pbuf->stream, &pbuf->m_data,
+ &pbuf->m_writable) < 0) {
+ GST_LOG_OBJECT (psink, "pa_stream_begin_write() failed");
+ goto writable_size_failed;
+ }
+
+ GST_LOG_OBJECT (psink, "got %" G_GSIZE_FORMAT " bytes of shared memory",
+ pbuf->m_writable);
+
+ }
+
+ if (towrite > pbuf->m_writable)
+ towrite = pbuf->m_writable;
+ avail = towrite / bps;
+
+ GST_LOG_OBJECT (psink, "writing %u samples at offset %" G_GUINT64_FORMAT,
+ (guint) avail, offset);
+
+#ifdef HAVE_PULSE_1_0
+ /* No trick modes for passthrough streams */
+ if (G_UNLIKELY (!pbuf->is_pcm && (inr != outr || reverse))) {
+ GST_WARNING_OBJECT (psink, "Passthrough stream can't run in trick mode");
+ goto unlock_and_fail;
+ }
+#endif
+
+ if (G_LIKELY (inr == outr && !reverse)) {
+ /* no rate conversion, simply write out the samples */
+ /* copy the data into internal buffer */
+
+ memcpy ((guint8 *) pbuf->m_data + pbuf->m_towrite, data, towrite);
+ pbuf->m_towrite += towrite;
+ pbuf->m_writable -= towrite;
+
+ data += towrite;
+ in_samples -= avail;
+ out_samples -= avail;
+ } else {
+ guint8 *dest, *d, *d_end;
+
+ /* write into the PulseAudio shm buffer */
+ dest = d = (guint8 *) pbuf->m_data + pbuf->m_towrite;
+ d_end = d + towrite;
+
+ if (!reverse) {
+ if (inr >= outr)
+ /* forward speed up */
+ FWD_UP_SAMPLES (data, data_end, d, d_end);
+ else
+ /* forward slow down */
+ FWD_DOWN_SAMPLES (data, data_end, d, d_end);
+ } else {
+ if (inr >= outr)
+ /* reverse speed up */
+ REV_UP_SAMPLES (data, data_end, d, d_end);
+ else
+ /* reverse slow down */
+ REV_DOWN_SAMPLES (data, data_end, d, d_end);
+ }
+ /* see what we have left to write */
+ towrite = (d - dest);
+ pbuf->m_towrite += towrite;
+ pbuf->m_writable -= towrite;
+
+ avail = towrite / bps;
+ }
+
+ /* flush the buffer if it's full */
+ if ((pbuf->m_data != NULL) && (pbuf->m_towrite > 0)
+ && (pbuf->m_writable == 0)) {
+ GST_LOG_OBJECT (psink, "flushing %u samples at offset %" G_GINT64_FORMAT,
+ (guint) pbuf->m_towrite / bps, pbuf->m_offset);
+
+ if (pa_stream_write (pbuf->stream, (uint8_t *) pbuf->m_data,
+ pbuf->m_towrite, NULL, pbuf->m_offset, PA_SEEK_ABSOLUTE) < 0) {
+ goto write_failed;
+ }
+ pbuf->m_towrite = 0;
+ pbuf->m_offset = offset + towrite; /* keep track of current offset */
+ }
+
+ *sample += avail;
+ offset += avail * bps;
+ pbuf->m_lastoffset = offset;
+
+ /* check if we need to uncork after writing the samples */
+ if (pbuf->corked) {
+ const pa_timing_info *info;
+
+ if ((info = pa_stream_get_timing_info (pbuf->stream))) {
+ GST_LOG_OBJECT (psink,
+ "read_index at %" G_GUINT64_FORMAT ", offset %" G_GINT64_FORMAT,
+ info->read_index, offset);
+
+ /* we uncork when the read_index is too far behind the offset we need
+ * to write to. */
+ if (info->read_index + bufsize <= offset) {
+ if (!gst_pulsering_set_corked (pbuf, FALSE, FALSE))
+ goto uncork_failed;
+ }
+ } else {
+ GST_LOG_OBJECT (psink, "no timing info available yet");
+ }
+ }
+ }
+
+#ifdef HAVE_PULSE_1_0
+fake_done:
+#endif
+ /* we consumed all samples here */
+ data = data_end + bps;
+
+ pbuf->in_commit = FALSE;
+ pa_threaded_mainloop_unlock (mainloop);
+
+done:
+ result = inr - ((data_end - data) / bps);
+ GST_LOG_OBJECT (psink, "wrote %d samples", result);
+
+ return result;
+
+ /* ERRORS */
+unlock_and_fail:
+ {
+ pbuf->in_commit = FALSE;
+ GST_LOG_OBJECT (psink, "we are reset");
+ pa_threaded_mainloop_unlock (mainloop);
+ goto done;
+ }
+no_start:
+ {
+ GST_LOG_OBJECT (psink, "we can not start");
+ return 0;
+ }
+start_failed:
+ {
+ GST_LOG_OBJECT (psink, "failed to start the ringbuffer");
+ return 0;
+ }
+uncork_failed:
+ {
+ pbuf->in_commit = FALSE;
+ GST_ERROR_OBJECT (psink, "uncork failed");
+ pa_threaded_mainloop_unlock (mainloop);
+ goto done;
+ }
+was_paused:
+ {
+ pbuf->in_commit = FALSE;
+ GST_LOG_OBJECT (psink, "we are paused");
+ pa_threaded_mainloop_unlock (mainloop);
+ goto done;
+ }
+writable_size_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_stream_writable_size() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock_and_fail;
+ }
+write_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_stream_write() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock_and_fail;
+ }
+}
+
+/* write pending local samples, must be called with the mainloop lock */
+static void
+gst_pulsering_flush (GstPulseRingBuffer * pbuf)
+{
+ GstPulseSink *psink;
+
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+ GST_DEBUG_OBJECT (psink, "entering flush");
+
+ /* flush the buffer if possible */
+ if (pbuf->stream && (pbuf->m_data != NULL) && (pbuf->m_towrite > 0)) {
+#ifndef GST_DISABLE_GST_DEBUG
+ gint bps;
+
+ bps = (GST_RING_BUFFER_CAST (pbuf))->spec.bytes_per_sample;
+ GST_LOG_OBJECT (psink,
+ "flushing %u samples at offset %" G_GINT64_FORMAT,
+ (guint) pbuf->m_towrite / bps, pbuf->m_offset);
+#endif
+
+ if (pa_stream_write (pbuf->stream, (uint8_t *) pbuf->m_data,
+ pbuf->m_towrite, NULL, pbuf->m_offset, PA_SEEK_ABSOLUTE) < 0) {
+ goto write_failed;
+ }
+
+ pbuf->m_towrite = 0;
+ pbuf->m_offset += pbuf->m_towrite; /* keep track of current offset */
+ }
+
+done:
+ return;
+
+ /* ERRORS */
+write_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_stream_write() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto done;
+ }
+}
+
+static void gst_pulsesink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_pulsesink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_pulsesink_finalize (GObject * object);
+
+static gboolean gst_pulsesink_event (GstBaseSink * sink, GstEvent * event);
+
+static GstStateChangeReturn gst_pulsesink_change_state (GstElement * element,
+ GstStateChange transition);
+
+static void gst_pulsesink_init_interfaces (GType type);
+
+GST_IMPLEMENT_PULSEPROBE_METHODS (GstPulseSink, gst_pulsesink);
+
+#define _do_init(type) \
+ gst_pulsesink_init_contexts (); \
+ gst_pulsesink_init_interfaces (type);
+
+GST_BOILERPLATE_FULL (GstPulseSink, gst_pulsesink, GstBaseAudioSink,
+ GST_TYPE_BASE_AUDIO_SINK, _do_init);
+
+static gboolean
+gst_pulsesink_interface_supported (GstImplementsInterface *
+ iface, GType interface_type)
+{
+ GstPulseSink *this = GST_PULSESINK_CAST (iface);
+
+ if (interface_type == GST_TYPE_PROPERTY_PROBE && this->probe)
+ return TRUE;
+ if (interface_type == GST_TYPE_STREAM_VOLUME)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+gst_pulsesink_implements_interface_init (GstImplementsInterfaceClass * klass)
+{
+ klass->supported = gst_pulsesink_interface_supported;
+}
+
+static void
+gst_pulsesink_init_interfaces (GType type)
+{
+ static const GInterfaceInfo implements_iface_info = {
+ (GInterfaceInitFunc) gst_pulsesink_implements_interface_init,
+ NULL,
+ NULL,
+ };
+ static const GInterfaceInfo probe_iface_info = {
+ (GInterfaceInitFunc) gst_pulsesink_property_probe_interface_init,
+ NULL,
+ NULL,
+ };
+ static const GInterfaceInfo svol_iface_info = {
+ NULL, NULL, NULL
+ };
+
+ g_type_add_interface_static (type, GST_TYPE_STREAM_VOLUME, &svol_iface_info);
+ g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
+ &implements_iface_info);
+ g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
+ &probe_iface_info);
+}
+
+static void
+gst_pulsesink_base_init (gpointer g_class)
+{
+ static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (PULSE_SINK_TEMPLATE_CAPS));
+
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details_simple (element_class,
+ "PulseAudio Audio Sink",
+ "Sink/Audio", "Plays audio to a PulseAudio server", "Lennart Poettering");
+ gst_element_class_add_static_pad_template (element_class, &pad_template);
+}
+
+static GstRingBuffer *
+gst_pulsesink_create_ringbuffer (GstBaseAudioSink * sink)
+{
+ GstRingBuffer *buffer;
+
+ GST_DEBUG_OBJECT (sink, "creating ringbuffer");
+ buffer = g_object_new (GST_TYPE_PULSERING_BUFFER, NULL);
+ GST_DEBUG_OBJECT (sink, "created ringbuffer @%p", buffer);
+
+ return buffer;
+}
+
+static GstBuffer *
+gst_pulsesink_payload (GstBaseAudioSink * sink, GstBuffer * buf)
+{
+ switch (sink->ringbuffer->spec.type) {
+ case GST_BUFTYPE_AC3:
+ case GST_BUFTYPE_EAC3:
+ case GST_BUFTYPE_DTS:
+ case GST_BUFTYPE_MPEG:
+ {
+ /* FIXME: alloc memory from PA if possible */
+ gint framesize = gst_audio_iec61937_frame_size (&sink->ringbuffer->spec);
+ GstBuffer *out;
+
+ if (framesize <= 0)
+ return NULL;
+
+ out = gst_buffer_new_and_alloc (framesize);
+
+ if (!gst_audio_iec61937_payload (GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf), GST_BUFFER_DATA (out),
+ GST_BUFFER_SIZE (out), &sink->ringbuffer->spec)) {
+ gst_buffer_unref (out);
+ return NULL;
+ }
+
+ gst_buffer_copy_metadata (out, buf, GST_BUFFER_COPY_ALL);
+ return out;
+ }
+
+ default:
+ return gst_buffer_ref (buf);
+ }
+}
+
+static void
+gst_pulsesink_class_init (GstPulseSinkClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
+ GstBaseSinkClass *bc;
+ GstBaseAudioSinkClass *gstaudiosink_class = GST_BASE_AUDIO_SINK_CLASS (klass);
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+ gchar *clientname;
+
+ gobject_class->finalize = gst_pulsesink_finalize;
+ gobject_class->set_property = gst_pulsesink_set_property;
+ gobject_class->get_property = gst_pulsesink_get_property;
+
+ gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_pulsesink_event);
+
+ /* restore the original basesink pull methods */
+ bc = g_type_class_peek (GST_TYPE_BASE_SINK);
+ gstbasesink_class->activate_pull = GST_DEBUG_FUNCPTR (bc->activate_pull);
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_pulsesink_change_state);
+
+ gstaudiosink_class->create_ringbuffer =
+ GST_DEBUG_FUNCPTR (gst_pulsesink_create_ringbuffer);
+ gstaudiosink_class->payload = GST_DEBUG_FUNCPTR (gst_pulsesink_payload);
+
+ /* Overwrite GObject fields */
+ g_object_class_install_property (gobject_class,
+ PROP_SERVER,
+ g_param_spec_string ("server", "Server",
+ "The PulseAudio server to connect to", DEFAULT_SERVER,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_DEVICE,
+ g_param_spec_string ("device", "Device",
+ "The PulseAudio sink device to connect to", DEFAULT_DEVICE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class,
+ PROP_DEVICE_NAME,
+ g_param_spec_string ("device-name", "Device name",
+ "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class,
+ PROP_VOLUME,
+ g_param_spec_double ("volume", "Volume",
+ "Linear volume of this stream, 1.0=100%", 0.0, MAX_VOLUME,
+ DEFAULT_VOLUME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_MUTE,
+ g_param_spec_boolean ("mute", "Mute",
+ "Mute state of this stream", DEFAULT_MUTE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstPulseSink:client
+ *
+ * The PulseAudio client name to use.
+ *
+ * Since: 0.10.25
+ */
+ clientname = gst_pulse_client_name ();
+ g_object_class_install_property (gobject_class,
+ PROP_CLIENT,
+ g_param_spec_string ("client", "Client",
+ "The PulseAudio client name to use", clientname,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ GST_PARAM_MUTABLE_READY));
+ g_free (clientname);
+
+ /**
+ * GstPulseSink:stream-properties
+ *
+ * List of pulseaudio stream properties. A list of defined properties can be
+ * found in the <ulink url="http://0pointer.de/lennart/projects/pulseaudio/doxygen/proplist_8h.html">pulseaudio api docs</ulink>.
+ *
+ * Below is an example for registering as a music application to pulseaudio.
+ * |[
+ * GstStructure *props;
+ *
+ * props = gst_structure_from_string ("props,media.role=music", NULL);
+ * g_object_set (pulse, "stream-properties", props, NULL);
+ * gst_structure_free
+ * ]|
+ *
+ * Since: 0.10.26
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_STREAM_PROPERTIES,
+ g_param_spec_boxed ("stream-properties", "stream properties",
+ "list of pulseaudio stream properties",
+ GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+/* returns the current time of the sink ringbuffer */
+static GstClockTime
+gst_pulsesink_get_time (GstClock * clock, GstBaseAudioSink * sink)
+{
+ GstPulseSink *psink;
+ GstPulseRingBuffer *pbuf;
+ pa_usec_t time;
+
+ if (!sink->ringbuffer || !sink->ringbuffer->acquired)
+ return GST_CLOCK_TIME_NONE;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (sink->ringbuffer);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+#ifdef HAVE_PULSE_1_0
+ if (g_atomic_int_get (&psink->format_lost)) {
+ /* Stream was lost in a format change, it'll get set up again once
+ * upstream renegotiates */
+ return psink->format_lost_time;
+ }
+#endif
+
+ pa_threaded_mainloop_lock (mainloop);
+ if (gst_pulsering_is_dead (psink, pbuf, TRUE))
+ goto server_dead;
+
+ /* if we don't have enough data to get a timestamp, just return NONE, which
+ * will return the last reported time */
+ if (pa_stream_get_time (pbuf->stream, &time) < 0) {
+ GST_DEBUG_OBJECT (psink, "could not get time");
+ time = GST_CLOCK_TIME_NONE;
+ } else
+ time *= 1000;
+ pa_threaded_mainloop_unlock (mainloop);
+
+ GST_LOG_OBJECT (psink, "current time is %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (time));
+
+ return time;
+
+ /* ERRORS */
+server_dead:
+ {
+ GST_DEBUG_OBJECT (psink, "the server is dead");
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return GST_CLOCK_TIME_NONE;
+ }
+}
+
+static void
+gst_pulsesink_sink_info_cb (pa_context * c, const pa_sink_info * i, int eol,
+ void *userdata)
+{
+ GstPulseRingBuffer *pbuf;
+ GstPulseSink *psink;
+#ifdef HAVE_PULSE_1_0
+ GList *l;
+ guint8 j;
+#endif
+
+ pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ if (!i)
+ goto done;
+
+ g_free (psink->device_description);
+ psink->device_description = g_strdup (i->description);
+
+#ifdef HAVE_PULSE_1_0
+ g_mutex_lock (psink->sink_formats_lock);
+
+ for (l = g_list_first (psink->sink_formats); l; l = g_list_next (l))
+ pa_format_info_free ((pa_format_info *) l->data);
+
+ g_list_free (psink->sink_formats);
+ psink->sink_formats = NULL;
+
+ for (j = 0; j < i->n_formats; j++)
+ psink->sink_formats = g_list_prepend (psink->sink_formats,
+ pa_format_info_copy (i->formats[j]));
+
+ g_mutex_unlock (psink->sink_formats_lock);
+#endif
+
+done:
+ pa_threaded_mainloop_signal (mainloop, 0);
+}
+
+#ifdef HAVE_PULSE_1_0
+/* NOTE: If you're making changes here, see if pulseaudiosink acceptcaps also
+ * needs to be changed accordingly. */
+static gboolean
+gst_pulsesink_pad_acceptcaps (GstPad * pad, GstCaps * caps)
+{
+ GstPulseSink *psink = GST_PULSESINK (gst_pad_get_parent_element (pad));
+ GstPulseRingBuffer *pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK
+ (psink)->ringbuffer);
+ GstCaps *pad_caps;
+ GstStructure *st;
+ gboolean ret = FALSE;
+
+ GstRingBufferSpec spec = { 0 };
+ pa_stream *stream = NULL;
+ pa_operation *o = NULL;
+ pa_channel_map channel_map;
+ pa_stream_flags_t flags;
+ pa_format_info *format = NULL, *formats[1];
+ guint channels;
+
+ pad_caps = gst_pad_get_caps_reffed (pad);
+ if (pad_caps) {
+ ret = gst_caps_can_intersect (pad_caps, caps);
+ gst_caps_unref (pad_caps);
+ }
+
+ /* Either template caps didn't match, or we're still in NULL state */
+ if (!ret || !pbuf->context)
+ goto done;
+
+ /* If we've not got fixed caps, creating a stream might fail, so let's just
+ * return from here with default acceptcaps behaviour */
+ if (!gst_caps_is_fixed (caps))
+ goto done;
+
+ ret = FALSE;
+
+ pa_threaded_mainloop_lock (mainloop);
+
+ spec.latency_time = GST_BASE_AUDIO_SINK (psink)->latency_time;
+ if (!gst_ring_buffer_parse_caps (&spec, caps))
+ goto out;
+
+ if (!gst_pulse_fill_format_info (&spec, &format, &channels))
+ goto out;
+
+ /* Make sure input is framed (one frame per buffer) and can be payloaded */
+ if (!pa_format_info_is_pcm (format)) {
+ gboolean framed = FALSE, parsed = FALSE;
+ st = gst_caps_get_structure (caps, 0);
+
+ gst_structure_get_boolean (st, "framed", &framed);
+ gst_structure_get_boolean (st, "parsed", &parsed);
+ if ((!framed && !parsed) || gst_audio_iec61937_frame_size (&spec) <= 0)
+ goto out;
+ }
+
+ /* initialize the channel map */
+ if (pa_format_info_is_pcm (format) &&
+ gst_pulse_gst_to_channel_map (&channel_map, &spec))
+ pa_format_info_set_channel_map (format, &channel_map);
+
+ if (pbuf->stream) {
+ /* We're already in PAUSED or above, so just reuse this stream to query
+ * sink formats and use those. */
+ GList *i;
+
+ if (!(o = pa_context_get_sink_info_by_name (pbuf->context, psink->device,
+ gst_pulsesink_sink_info_cb, pbuf)))
+ goto info_failed;
+
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+ pa_threaded_mainloop_wait (mainloop);
+ if (gst_pulsering_is_dead (psink, pbuf, TRUE))
+ goto out;
+ }
+
+ g_mutex_lock (psink->sink_formats_lock);
+ for (i = g_list_first (psink->sink_formats); i; i = g_list_next (i)) {
+ if (pa_format_info_is_compatible ((pa_format_info *) i->data, format)) {
+ ret = TRUE;
+ break;
+ }
+ }
+ g_mutex_unlock (psink->sink_formats_lock);
+ } else {
+ /* We're in READY, let's connect a stream to see if the format is
+ * accpeted by whatever sink we're routed to */
+ formats[0] = format;
+
+ if (!(stream = pa_stream_new_extended (pbuf->context, "pulsesink probe",
+ formats, 1, psink->proplist)))
+ goto out;
+
+ /* construct the flags */
+ flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
+ PA_STREAM_ADJUST_LATENCY | PA_STREAM_START_CORKED;
+
+ pa_stream_set_state_callback (stream, gst_pulsering_stream_state_cb, pbuf);
+
+ if (pa_stream_connect_playback (stream, psink->device, NULL, flags, NULL,
+ NULL) < 0)
+ goto out;
+
+ ret = gst_pulsering_wait_for_stream_ready (psink, stream);
+ }
+
+out:
+ if (format)
+ pa_format_info_free (format);
+
+ if (o)
+ pa_operation_unref (o);
+
+ if (stream) {
+ pa_stream_set_state_callback (stream, NULL, NULL);
+ pa_stream_disconnect (stream);
+ pa_stream_unref (stream);
+ }
+
+ pa_threaded_mainloop_unlock (mainloop);
+
+done:
+ gst_object_unref (psink);
+ return ret;
+
+info_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_context_get_sink_input_info() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto out;
+ }
+}
+#endif
+
+static void
+gst_pulsesink_init (GstPulseSink * pulsesink, GstPulseSinkClass * klass)
+{
+ pulsesink->server = NULL;
+ pulsesink->device = NULL;
+ pulsesink->device_description = NULL;
+ pulsesink->client_name = gst_pulse_client_name ();
+
+#ifdef HAVE_PULSE_1_0
+ pulsesink->sink_formats_lock = g_mutex_new ();
+ pulsesink->sink_formats = NULL;
+#endif
+
+ pulsesink->volume = DEFAULT_VOLUME;
+ pulsesink->volume_set = FALSE;
+
+ pulsesink->mute = DEFAULT_MUTE;
+ pulsesink->mute_set = FALSE;
+
+ pulsesink->notify = 0;
+
+#ifdef HAVE_PULSE_1_0
+ g_atomic_int_set (&pulsesink->format_lost, FALSE);
+ pulsesink->format_lost_time = GST_CLOCK_TIME_NONE;
+#endif
+
+ pulsesink->properties = NULL;
+ pulsesink->proplist = NULL;
+
+ /* override with a custom clock */
+ if (GST_BASE_AUDIO_SINK (pulsesink)->provided_clock)
+ gst_object_unref (GST_BASE_AUDIO_SINK (pulsesink)->provided_clock);
+
+ GST_BASE_AUDIO_SINK (pulsesink)->provided_clock =
+ gst_audio_clock_new ("GstPulseSinkClock",
+ (GstAudioClockGetTimeFunc) gst_pulsesink_get_time, pulsesink);
+
+#ifdef HAVE_PULSE_1_0
+ gst_pad_set_acceptcaps_function (GST_BASE_SINK (pulsesink)->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_pulsesink_pad_acceptcaps));
+#endif
+
+ /* TRUE for sinks, FALSE for sources */
+ pulsesink->probe = gst_pulseprobe_new (G_OBJECT (pulsesink),
+ G_OBJECT_GET_CLASS (pulsesink), PROP_DEVICE, pulsesink->device,
+ TRUE, FALSE);
+}
+
+static void
+gst_pulsesink_finalize (GObject * object)
+{
+ GstPulseSink *pulsesink = GST_PULSESINK_CAST (object);
+#ifdef HAVE_PULSE_1_0
+ GList *i;
+#endif
+
+ g_free (pulsesink->server);
+ g_free (pulsesink->device);
+ g_free (pulsesink->device_description);
+ g_free (pulsesink->client_name);
+
+#ifdef HAVE_PULSE_1_0
+ for (i = g_list_first (pulsesink->sink_formats); i; i = g_list_next (i))
+ pa_format_info_free ((pa_format_info *) i->data);
+
+ g_list_free (pulsesink->sink_formats);
+ g_mutex_free (pulsesink->sink_formats_lock);
+#endif
+
+ if (pulsesink->properties)
+ gst_structure_free (pulsesink->properties);
+ if (pulsesink->proplist)
+ pa_proplist_free (pulsesink->proplist);
+
+ if (pulsesink->probe) {
+ gst_pulseprobe_free (pulsesink->probe);
+ pulsesink->probe = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_pulsesink_set_volume (GstPulseSink * psink, gdouble volume)
+{
+ pa_cvolume v;
+ pa_operation *o = NULL;
+ GstPulseRingBuffer *pbuf;
+ uint32_t idx;
+
+ if (!mainloop)
+ goto no_mainloop;
+
+ pa_threaded_mainloop_lock (mainloop);
+
+ GST_DEBUG_OBJECT (psink, "setting volume to %f", volume);
+
+ pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
+ if (pbuf == NULL || pbuf->stream == NULL)
+ goto no_buffer;
+
+ if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
+ goto no_index;
+
+#ifdef HAVE_PULSE_1_0
+ if (pbuf->is_pcm)
+ gst_pulse_cvolume_from_linear (&v, pbuf->channels, volume);
+ else
+ /* FIXME: this will eventually be superceded by checks to see if the volume
+ * is readable/writable */
+ goto unlock;
+#else
+ gst_pulse_cvolume_from_linear (&v, pbuf->sample_spec.channels, volume);
+#endif
+
+ if (!(o = pa_context_set_sink_input_volume (pbuf->context, idx,
+ &v, NULL, NULL)))
+ goto volume_failed;
+
+ /* We don't really care about the result of this call */
+unlock:
+
+ if (o)
+ pa_operation_unref (o);
+
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return;
+
+ /* ERRORS */
+no_mainloop:
+ {
+ psink->volume = volume;
+ psink->volume_set = TRUE;
+
+ GST_DEBUG_OBJECT (psink, "we have no mainloop");
+ return;
+ }
+no_buffer:
+ {
+ psink->volume = volume;
+ psink->volume_set = TRUE;
+
+ GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+ goto unlock;
+ }
+no_index:
+ {
+ GST_DEBUG_OBJECT (psink, "we don't have a stream index");
+ goto unlock;
+ }
+volume_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_stream_set_sink_input_volume() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock;
+ }
+}
+
+static void
+gst_pulsesink_set_mute (GstPulseSink * psink, gboolean mute)
+{
+ pa_operation *o = NULL;
+ GstPulseRingBuffer *pbuf;
+ uint32_t idx;
+
+ if (!mainloop)
+ goto no_mainloop;
+
+ pa_threaded_mainloop_lock (mainloop);
+
+ GST_DEBUG_OBJECT (psink, "setting mute state to %d", mute);
+
+ pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
+ if (pbuf == NULL || pbuf->stream == NULL)
+ goto no_buffer;
+
+ if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
+ goto no_index;
+
+ if (!(o = pa_context_set_sink_input_mute (pbuf->context, idx,
+ mute, NULL, NULL)))
+ goto mute_failed;
+
+ /* We don't really care about the result of this call */
+unlock:
+
+ if (o)
+ pa_operation_unref (o);
+
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return;
+
+ /* ERRORS */
+no_mainloop:
+ {
+ psink->mute = mute;
+ psink->mute_set = TRUE;
+
+ GST_DEBUG_OBJECT (psink, "we have no mainloop");
+ return;
+ }
+no_buffer:
+ {
+ psink->mute = mute;
+ psink->mute_set = TRUE;
+
+ GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+ goto unlock;
+ }
+no_index:
+ {
+ GST_DEBUG_OBJECT (psink, "we don't have a stream index");
+ goto unlock;
+ }
+mute_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_stream_set_sink_input_mute() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock;
+ }
+}
+
+static void
+gst_pulsesink_sink_input_info_cb (pa_context * c, const pa_sink_input_info * i,
+ int eol, void *userdata)
+{
+ GstPulseRingBuffer *pbuf;
+ GstPulseSink *psink;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (userdata);
+ psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
+
+ if (!i)
+ goto done;
+
+ if (!pbuf->stream)
+ goto done;
+
+ /* If the index doesn't match our current stream,
+ * it implies we just recreated the stream (caps change)
+ */
+ if (i->index == pa_stream_get_index (pbuf->stream)) {
+ psink->volume = pa_sw_volume_to_linear (pa_cvolume_max (&i->volume));
+ psink->mute = i->mute;
+ }
+
+done:
+ pa_threaded_mainloop_signal (mainloop, 0);
+}
+
+static gdouble
+gst_pulsesink_get_volume (GstPulseSink * psink)
+{
+ GstPulseRingBuffer *pbuf;
+ pa_operation *o = NULL;
+ gdouble v = DEFAULT_VOLUME;
+ uint32_t idx;
+
+ if (!mainloop)
+ goto no_mainloop;
+
+ pa_threaded_mainloop_lock (mainloop);
+
+ pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
+ if (pbuf == NULL || pbuf->stream == NULL)
+ goto no_buffer;
+
+ if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
+ goto no_index;
+
+ if (!(o = pa_context_get_sink_input_info (pbuf->context, idx,
+ gst_pulsesink_sink_input_info_cb, pbuf)))
+ goto info_failed;
+
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+ pa_threaded_mainloop_wait (mainloop);
+ if (gst_pulsering_is_dead (psink, pbuf, TRUE))
+ goto unlock;
+ }
+
+unlock:
+ v = psink->volume;
+
+ if (o)
+ pa_operation_unref (o);
+
+ pa_threaded_mainloop_unlock (mainloop);
+
+ if (v > MAX_VOLUME) {
+ GST_WARNING_OBJECT (psink, "Clipped volume from %f to %f", v, MAX_VOLUME);
+ v = MAX_VOLUME;
+ }
+
+ return v;
+
+ /* ERRORS */
+no_mainloop:
+ {
+ v = psink->volume;
+ GST_DEBUG_OBJECT (psink, "we have no mainloop");
+ return v;
+ }
+no_buffer:
+ {
+ GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+ goto unlock;
+ }
+no_index:
+ {
+ GST_DEBUG_OBJECT (psink, "we don't have a stream index");
+ goto unlock;
+ }
+info_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_context_get_sink_input_info() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock;
+ }
+}
+
+static gboolean
+gst_pulsesink_get_mute (GstPulseSink * psink)
+{
+ GstPulseRingBuffer *pbuf;
+ pa_operation *o = NULL;
+ uint32_t idx;
+ gboolean mute = FALSE;
+
+ if (!mainloop)
+ goto no_mainloop;
+
+ pa_threaded_mainloop_lock (mainloop);
+ mute = psink->mute;
+
+ pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
+ if (pbuf == NULL || pbuf->stream == NULL)
+ goto no_buffer;
+
+ if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
+ goto no_index;
+
+ if (!(o = pa_context_get_sink_input_info (pbuf->context, idx,
+ gst_pulsesink_sink_input_info_cb, pbuf)))
+ goto info_failed;
+
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+ pa_threaded_mainloop_wait (mainloop);
+ if (gst_pulsering_is_dead (psink, pbuf, TRUE))
+ goto unlock;
+ }
+
+unlock:
+ if (o)
+ pa_operation_unref (o);
+
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return mute;
+
+ /* ERRORS */
+no_mainloop:
+ {
+ mute = psink->mute;
+ GST_DEBUG_OBJECT (psink, "we have no mainloop");
+ return mute;
+ }
+no_buffer:
+ {
+ GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+ goto unlock;
+ }
+no_index:
+ {
+ GST_DEBUG_OBJECT (psink, "we don't have a stream index");
+ goto unlock;
+ }
+info_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_context_get_sink_input_info() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock;
+ }
+}
+
+static gchar *
+gst_pulsesink_device_description (GstPulseSink * psink)
+{
+ GstPulseRingBuffer *pbuf;
+ pa_operation *o = NULL;
+ gchar *t;
+
+ if (!mainloop)
+ goto no_mainloop;
+
+ pa_threaded_mainloop_lock (mainloop);
+ pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
+ if (pbuf == NULL)
+ goto no_buffer;
+
+ if (!(o = pa_context_get_sink_info_by_name (pbuf->context,
+ psink->device, gst_pulsesink_sink_info_cb, pbuf)))
+ goto info_failed;
+
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+ pa_threaded_mainloop_wait (mainloop);
+ if (gst_pulsering_is_dead (psink, pbuf, FALSE))
+ goto unlock;
+ }
+
+unlock:
+ if (o)
+ pa_operation_unref (o);
+
+ t = g_strdup (psink->device_description);
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return t;
+
+ /* ERRORS */
+no_mainloop:
+ {
+ GST_DEBUG_OBJECT (psink, "we have no mainloop");
+ return NULL;
+ }
+no_buffer:
+ {
+ GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+ goto unlock;
+ }
+info_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_context_get_sink_info_by_index() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock;
+ }
+}
+
+static void
+gst_pulsesink_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstPulseSink *pulsesink = GST_PULSESINK_CAST (object);
+
+ switch (prop_id) {
+ case PROP_SERVER:
+ g_free (pulsesink->server);
+ pulsesink->server = g_value_dup_string (value);
+ if (pulsesink->probe)
+ gst_pulseprobe_set_server (pulsesink->probe, pulsesink->server);
+ break;
+ case PROP_DEVICE:
+ g_free (pulsesink->device);
+ pulsesink->device = g_value_dup_string (value);
+ break;
+ case PROP_VOLUME:
+ gst_pulsesink_set_volume (pulsesink, g_value_get_double (value));
+ break;
+ case PROP_MUTE:
+ gst_pulsesink_set_mute (pulsesink, g_value_get_boolean (value));
+ break;
+ case PROP_CLIENT:
+ g_free (pulsesink->client_name);
+ if (!g_value_get_string (value)) {
+ GST_WARNING_OBJECT (pulsesink,
+ "Empty PulseAudio client name not allowed. Resetting to default value");
+ pulsesink->client_name = gst_pulse_client_name ();
+ } else
+ pulsesink->client_name = g_value_dup_string (value);
+ break;
+ case PROP_STREAM_PROPERTIES:
+ if (pulsesink->properties)
+ gst_structure_free (pulsesink->properties);
+ pulsesink->properties =
+ gst_structure_copy (gst_value_get_structure (value));
+ if (pulsesink->proplist)
+ pa_proplist_free (pulsesink->proplist);
+ pulsesink->proplist = gst_pulse_make_proplist (pulsesink->properties);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_pulsesink_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+
+ GstPulseSink *pulsesink = GST_PULSESINK_CAST (object);
+
+ switch (prop_id) {
+ case PROP_SERVER:
+ g_value_set_string (value, pulsesink->server);
+ break;
+ case PROP_DEVICE:
+ g_value_set_string (value, pulsesink->device);
+ break;
+ case PROP_DEVICE_NAME:
+ g_value_take_string (value, gst_pulsesink_device_description (pulsesink));
+ break;
+ case PROP_VOLUME:
+ g_value_set_double (value, gst_pulsesink_get_volume (pulsesink));
+ break;
+ case PROP_MUTE:
+ g_value_set_boolean (value, gst_pulsesink_get_mute (pulsesink));
+ break;
+ case PROP_CLIENT:
+ g_value_set_string (value, pulsesink->client_name);
+ break;
+ case PROP_STREAM_PROPERTIES:
+ gst_value_set_structure (value, pulsesink->properties);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_pulsesink_change_title (GstPulseSink * psink, const gchar * t)
+{
+ pa_operation *o = NULL;
+ GstPulseRingBuffer *pbuf;
+
+ pa_threaded_mainloop_lock (mainloop);
+
+ pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
+
+ if (pbuf == NULL || pbuf->stream == NULL)
+ goto no_buffer;
+
+ g_free (pbuf->stream_name);
+ pbuf->stream_name = g_strdup (t);
+
+ if (!(o = pa_stream_set_name (pbuf->stream, pbuf->stream_name, NULL, NULL)))
+ goto name_failed;
+
+ /* We're not interested if this operation failed or not */
+unlock:
+
+ if (o)
+ pa_operation_unref (o);
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return;
+
+ /* ERRORS */
+no_buffer:
+ {
+ GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+ goto unlock;
+ }
+name_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_stream_set_name() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock;
+ }
+}
+
+static void
+gst_pulsesink_change_props (GstPulseSink * psink, GstTagList * l)
+{
+ static const gchar *const map[] = {
+ GST_TAG_TITLE, PA_PROP_MEDIA_TITLE,
+
+ /* might get overriden in the next iteration by GST_TAG_ARTIST */
+ GST_TAG_PERFORMER, PA_PROP_MEDIA_ARTIST,
+
+ GST_TAG_ARTIST, PA_PROP_MEDIA_ARTIST,
+ GST_TAG_LANGUAGE_CODE, PA_PROP_MEDIA_LANGUAGE,
+ GST_TAG_LOCATION, PA_PROP_MEDIA_FILENAME,
+ /* We might add more here later on ... */
+ NULL
+ };
+ pa_proplist *pl = NULL;
+ const gchar *const *t;
+ gboolean empty = TRUE;
+ pa_operation *o = NULL;
+ GstPulseRingBuffer *pbuf;
+
+ pl = pa_proplist_new ();
+
+ for (t = map; *t; t += 2) {
+ gchar *n = NULL;
+
+ if (gst_tag_list_get_string (l, *t, &n)) {
+
+ if (n && *n) {
+ pa_proplist_sets (pl, *(t + 1), n);
+ empty = FALSE;
+ }
+
+ g_free (n);
+ }
+ }
+ if (empty)
+ goto finish;
+
+ pa_threaded_mainloop_lock (mainloop);
+ pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
+ if (pbuf == NULL || pbuf->stream == NULL)
+ goto no_buffer;
+
+ if (!(o = pa_stream_proplist_update (pbuf->stream, PA_UPDATE_REPLACE,
+ pl, NULL, NULL)))
+ goto update_failed;
+
+ /* We're not interested if this operation failed or not */
+unlock:
+
+ if (o)
+ pa_operation_unref (o);
+
+ pa_threaded_mainloop_unlock (mainloop);
+
+finish:
+
+ if (pl)
+ pa_proplist_free (pl);
+
+ return;
+
+ /* ERRORS */
+no_buffer:
+ {
+ GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+ goto unlock;
+ }
+update_failed:
+ {
+ GST_ELEMENT_ERROR (psink, RESOURCE, FAILED,
+ ("pa_stream_proplist_update() failed: %s",
+ pa_strerror (pa_context_errno (pbuf->context))), (NULL));
+ goto unlock;
+ }
+}
+
+static void
+gst_pulsesink_flush_ringbuffer (GstPulseSink * psink)
+{
+ GstPulseRingBuffer *pbuf;
+
+ pa_threaded_mainloop_lock (mainloop);
+
+ pbuf = GST_PULSERING_BUFFER_CAST (GST_BASE_AUDIO_SINK (psink)->ringbuffer);
+
+ if (pbuf == NULL || pbuf->stream == NULL)
+ goto no_buffer;
+
+ gst_pulsering_flush (pbuf);
+
+ /* Uncork if we haven't already (happens when waiting to get enough data
+ * to send out the first time) */
+ if (pbuf->corked)
+ gst_pulsering_set_corked (pbuf, FALSE, FALSE);
+
+ /* We're not interested if this operation failed or not */
+unlock:
+ pa_threaded_mainloop_unlock (mainloop);
+
+ return;
+
+ /* ERRORS */
+no_buffer:
+ {
+ GST_DEBUG_OBJECT (psink, "we have no ringbuffer");
+ goto unlock;
+ }
+}
+
+static gboolean
+gst_pulsesink_event (GstBaseSink * sink, GstEvent * event)
+{
+ GstPulseSink *pulsesink = GST_PULSESINK_CAST (sink);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_TAG:{
+ gchar *title = NULL, *artist = NULL, *location = NULL, *description =
+ NULL, *t = NULL, *buf = NULL;
+ GstTagList *l;
+
+ gst_event_parse_tag (event, &l);
+
+ gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
+ gst_tag_list_get_string (l, GST_TAG_ARTIST, &artist);
+ gst_tag_list_get_string (l, GST_TAG_LOCATION, &location);
+ gst_tag_list_get_string (l, GST_TAG_DESCRIPTION, &description);
+
+ if (!artist)
+ gst_tag_list_get_string (l, GST_TAG_PERFORMER, &artist);
+
+ if (title && artist)
+ /* TRANSLATORS: 'song title' by 'artist name' */
+ t = buf = g_strdup_printf (_("'%s' by '%s'"), g_strstrip (title),
+ g_strstrip (artist));
+ else if (title)
+ t = g_strstrip (title);
+ else if (description)
+ t = g_strstrip (description);
+ else if (location)
+ t = g_strstrip (location);
+
+ if (t)
+ gst_pulsesink_change_title (pulsesink, t);
+
+ g_free (title);
+ g_free (artist);
+ g_free (location);
+ g_free (description);
+ g_free (buf);
+
+ gst_pulsesink_change_props (pulsesink, l);
+
+ break;
+ }
+ case GST_EVENT_EOS:
+ gst_pulsesink_flush_ringbuffer (pulsesink);
+ break;
+ default:
+ ;
+ }
+
+ return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
+}
+
+static void
+gst_pulsesink_release_mainloop (GstPulseSink * psink)
+{
+ if (!mainloop)
+ return;
+
+ pa_threaded_mainloop_lock (mainloop);
+ while (psink->defer_pending) {
+ GST_DEBUG_OBJECT (psink, "waiting for stream status message emission");
+ pa_threaded_mainloop_wait (mainloop);
+ }
+ pa_threaded_mainloop_unlock (mainloop);
+
+ g_mutex_lock (pa_shared_resource_mutex);
+ mainloop_ref_ct--;
+ if (!mainloop_ref_ct) {
+ GST_INFO_OBJECT (psink, "terminating pa main loop thread");
+ pa_threaded_mainloop_stop (mainloop);
+ pa_threaded_mainloop_free (mainloop);
+ mainloop = NULL;
+ }
+ g_mutex_unlock (pa_shared_resource_mutex);
+}
+
+static GstStateChangeReturn
+gst_pulsesink_change_state (GstElement * element, GstStateChange transition)
+{
+ GstPulseSink *pulsesink = GST_PULSESINK (element);
+ GstStateChangeReturn ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ g_mutex_lock (pa_shared_resource_mutex);
+ if (!mainloop_ref_ct) {
+ GST_INFO_OBJECT (element, "new pa main loop thread");
+ if (!(mainloop = pa_threaded_mainloop_new ()))
+ goto mainloop_failed;
+ if (pa_threaded_mainloop_start (mainloop) < 0) {
+ pa_threaded_mainloop_free (mainloop);
+ goto mainloop_start_failed;
+ }
+ mainloop_ref_ct = 1;
+ g_mutex_unlock (pa_shared_resource_mutex);
+ } else {
+ GST_INFO_OBJECT (element, "reusing pa main loop thread");
+ mainloop_ref_ct++;
+ g_mutex_unlock (pa_shared_resource_mutex);
+ }
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_element_post_message (element,
+ gst_message_new_clock_provide (GST_OBJECT_CAST (element),
+ GST_BASE_AUDIO_SINK (pulsesink)->provided_clock, TRUE));
+ break;
+
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ goto state_failure;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ /* format_lost is reset in release() in baseaudiosink */
+ gst_element_post_message (element,
+ gst_message_new_clock_lost (GST_OBJECT_CAST (element),
+ GST_BASE_AUDIO_SINK (pulsesink)->provided_clock));
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ gst_pulsesink_release_mainloop (pulsesink);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+
+ /* ERRORS */
+mainloop_failed:
+ {
+ g_mutex_unlock (pa_shared_resource_mutex);
+ GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
+ ("pa_threaded_mainloop_new() failed"), (NULL));
+ return GST_STATE_CHANGE_FAILURE;
+ }
+mainloop_start_failed:
+ {
+ g_mutex_unlock (pa_shared_resource_mutex);
+ GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
+ ("pa_threaded_mainloop_start() failed"), (NULL));
+ return GST_STATE_CHANGE_FAILURE;
+ }
+state_failure:
+ {
+ if (transition == GST_STATE_CHANGE_NULL_TO_READY) {
+ /* Clear the PA mainloop if baseaudiosink failed to open the ring_buffer */
+ g_assert (mainloop);
+ gst_pulsesink_release_mainloop (pulsesink);
+ }
+ return ret;
+ }
+}
diff --git a/ext/pulse/pulsesink.h b/ext/pulse/pulsesink.h
new file mode 100644
index 0000000..340b481
--- /dev/null
+++ b/ext/pulse/pulsesink.h
@@ -0,0 +1,182 @@
+/*-*- Mode: C; c-basic-offset: 2 -*-*/
+
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifndef __GST_PULSESINK_H__
+#define __GST_PULSESINK_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosink.h>
+
+#include <pulse/pulseaudio.h>
+#include <pulse/thread-mainloop.h>
+
+#include "pulseprobe.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PULSESINK \
+ (gst_pulsesink_get_type())
+#define GST_PULSESINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PULSESINK,GstPulseSink))
+#define GST_PULSESINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PULSESINK,GstPulseSinkClass))
+#define GST_IS_PULSESINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PULSESINK))
+#define GST_IS_PULSESINK_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PULSESINK))
+#define GST_PULSESINK_CAST(obj) \
+ ((GstPulseSink *)(obj))
+
+typedef struct _GstPulseSink GstPulseSink;
+typedef struct _GstPulseSinkClass GstPulseSinkClass;
+
+struct _GstPulseSink
+{
+ GstBaseAudioSink sink;
+
+ gchar *server, *device, *stream_name, *client_name;
+ gchar *device_description;
+
+ GstPulseProbe *probe;
+
+ gdouble volume;
+ gboolean volume_set:1;
+ gboolean mute:1;
+ gboolean mute_set:1;
+
+ guint defer_pending;
+
+ gint notify; /* atomic */
+
+ const gchar *pa_version;
+
+ GstStructure *properties;
+ pa_proplist *proplist;
+
+#ifdef HAVE_PULSE_1_0
+ GMutex *sink_formats_lock;
+ GList *sink_formats;
+ volatile gint format_lost;
+ GstClockTime format_lost_time;
+#endif
+};
+
+struct _GstPulseSinkClass
+{
+ GstBaseAudioSinkClass parent_class;
+};
+
+GType gst_pulsesink_get_type (void);
+
+#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
+# define ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN"
+#else
+# define ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN"
+#endif
+
+#define _PULSE_SINK_CAPS_COMMON \
+ "audio/x-raw-int, " \
+ "endianness = (int) { " ENDIANNESS " }, " \
+ "signed = (boolean) TRUE, " \
+ "width = (int) 16, " \
+ "depth = (int) 16, " \
+ "rate = (int) [ 1, MAX ], " \
+ "channels = (int) [ 1, 32 ];" \
+ "audio/x-raw-float, " \
+ "endianness = (int) { " ENDIANNESS " }, " \
+ "width = (int) 32, " \
+ "rate = (int) [ 1, MAX ], " \
+ "channels = (int) [ 1, 32 ];" \
+ "audio/x-raw-int, " \
+ "endianness = (int) { " ENDIANNESS " }, " \
+ "signed = (boolean) TRUE, " \
+ "width = (int) 32, " \
+ "depth = (int) 32, " \
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 32 ];" \
+ "audio/x-raw-int, " \
+ "signed = (boolean) FALSE, " \
+ "width = (int) 8, " \
+ "depth = (int) 8, " \
+ "rate = (int) [ 1, MAX ], " \
+ "channels = (int) [ 1, 32 ];" \
+ "audio/x-alaw, " \
+ "rate = (int) [ 1, MAX], " \
+ "channels = (int) [ 1, 32 ];" \
+ "audio/x-mulaw, " \
+ "rate = (int) [ 1, MAX], " "channels = (int) [ 1, 32 ];" \
+ "audio/x-raw-int, " \
+ "endianness = (int) { " ENDIANNESS " }, " \
+ "signed = (boolean) TRUE, " \
+ "width = (int) 24, " \
+ "depth = (int) 24, " \
+ "rate = (int) [ 1, MAX ], " \
+ "channels = (int) [ 1, 32 ];" \
+ "audio/x-raw-int, " \
+ "endianness = (int) { " ENDIANNESS " }, " \
+ "signed = (boolean) TRUE, " \
+ "width = (int) 32, " \
+ "depth = (int) 24, " \
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 32 ];"
+
+#ifdef HAVE_PULSE_1_0
+#define _PULSE_SINK_CAPS_1_0 \
+ "audio/x-ac3, framed = (boolean) true;" \
+ "audio/x-eac3, framed = (boolean) true; " \
+ "audio/x-dts, framed = (boolean) true, " \
+ "block-size = (int) { 512, 1024, 2048 }; " \
+ "audio/mpeg, mpegversion = (int) 1, " \
+ "mpegaudioversion = (int) [ 1, 2 ], parsed = (boolean) true;"
+#else
+#define _PULSE_SINK_CAPS_1_0 ""
+#endif
+
+#define PULSE_SINK_TEMPLATE_CAPS \
+ _PULSE_SINK_CAPS_COMMON \
+ _PULSE_SINK_CAPS_1_0
+
+#ifdef HAVE_PULSE_1_0
+
+#define GST_TYPE_PULSE_AUDIO_SINK \
+ (gst_pulse_audio_sink_get_type())
+#define GST_PULSE_AUDIO_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PULSE_AUDIO_SINK,GstPulseAudioSink))
+#define GST_PULSE_AUDIO_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PULSE_AUDIO_SINK,GstPulseAudioSinkClass))
+#define GST_IS_PULSE_AUDIO_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PULSE_AUDIO_SINK))
+#define GST_IS_PULSE_AUDIO_SINK_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PULSE_AUDIO_SINK))
+#define GST_PULSE_AUDIO_SINK_CAST(obj) \
+ ((GstPulseAudioSink *)(obj))
+
+GType gst_pulse_audio_sink_get_type (void);
+
+#endif /* HAVE_PULSE_1_0 */
+
+G_END_DECLS
+
+#endif /* __GST_PULSESINK_H__ */
diff --git a/ext/pulse/pulsesrc.c b/ext/pulse/pulsesrc.c
new file mode 100644
index 0000000..12e5282
--- /dev/null
+++ b/ext/pulse/pulsesrc.c
@@ -0,0 +1,1750 @@
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+/**
+ * SECTION:element-pulsesrc
+ * @see_also: pulsesink, pulsemixer
+ *
+ * This element captures audio from a
+ * <ulink href="http://www.pulseaudio.org">PulseAudio sound server</ulink>.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch -v pulsesrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg
+ * ]| Record from a sound card using pulseaudio and encode to Ogg/Vorbis.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include <gst/base/gstbasesrc.h>
+#include <gst/gsttaglist.h>
+#ifdef HAVE_PULSE_1_0
+#include <gst/interfaces/streamvolume.h>
+#endif
+
+#include "pulsesrc.h"
+#include "pulseutil.h"
+#include "pulsemixerctrl.h"
+
+GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
+#define GST_CAT_DEFAULT pulse_debug
+
+#define DEFAULT_SERVER NULL
+#define DEFAULT_DEVICE NULL
+#define DEFAULT_DEVICE_NAME NULL
+
+#ifdef HAVE_PULSE_1_0
+#define DEFAULT_VOLUME 1.0
+#define DEFAULT_MUTE FALSE
+#define MAX_VOLUME 10.0
+#endif
+
+enum
+{
+ PROP_0,
+ PROP_SERVER,
+ PROP_DEVICE,
+ PROP_DEVICE_NAME,
+ PROP_CLIENT,
+ PROP_STREAM_PROPERTIES,
+ PROP_SOURCE_OUTPUT_INDEX,
+#ifdef HAVE_PULSE_1_0
+ PROP_VOLUME,
+ PROP_MUTE,
+#endif
+ PROP_LAST
+};
+
+static void gst_pulsesrc_destroy_stream (GstPulseSrc * pulsesrc);
+static void gst_pulsesrc_destroy_context (GstPulseSrc * pulsesrc);
+
+static void gst_pulsesrc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_pulsesrc_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_pulsesrc_finalize (GObject * object);
+
+static gboolean gst_pulsesrc_open (GstAudioSrc * asrc);
+
+static gboolean gst_pulsesrc_close (GstAudioSrc * asrc);
+
+static gboolean gst_pulsesrc_prepare (GstAudioSrc * asrc,
+ GstRingBufferSpec * spec);
+
+static gboolean gst_pulsesrc_unprepare (GstAudioSrc * asrc);
+
+static guint gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data,
+ guint length);
+static guint gst_pulsesrc_delay (GstAudioSrc * asrc);
+
+static void gst_pulsesrc_reset (GstAudioSrc * src);
+
+static gboolean gst_pulsesrc_negotiate (GstBaseSrc * basesrc);
+
+static GstStateChangeReturn gst_pulsesrc_change_state (GstElement *
+ element, GstStateChange transition);
+
+static void gst_pulsesrc_init_interfaces (GType type);
+
+#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
+# define ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN"
+#else
+# define ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN"
+#endif
+
+GST_IMPLEMENT_PULSEMIXER_CTRL_METHODS (GstPulseSrc, gst_pulsesrc);
+GST_IMPLEMENT_PULSEPROBE_METHODS (GstPulseSrc, gst_pulsesrc);
+GST_BOILERPLATE_FULL (GstPulseSrc, gst_pulsesrc, GstAudioSrc,
+ GST_TYPE_AUDIO_SRC, gst_pulsesrc_init_interfaces);
+
+static gboolean
+gst_pulsesrc_interface_supported (GstImplementsInterface *
+ iface, GType interface_type)
+{
+ GstPulseSrc *this = GST_PULSESRC_CAST (iface);
+
+ if (interface_type == GST_TYPE_MIXER && this->mixer)
+ return TRUE;
+
+ if (interface_type == GST_TYPE_PROPERTY_PROBE && this->probe)
+ return TRUE;
+
+#ifdef HAVE_PULSE_1_0
+ if (interface_type == GST_TYPE_STREAM_VOLUME)
+ return TRUE;
+#endif
+
+ return FALSE;
+}
+
+static void
+gst_pulsesrc_implements_interface_init (GstImplementsInterfaceClass * klass)
+{
+ klass->supported = gst_pulsesrc_interface_supported;
+}
+
+static void
+gst_pulsesrc_init_interfaces (GType type)
+{
+#ifdef HAVE_PULSE_1_0
+ static const GInterfaceInfo svol_iface_info = {
+ NULL, NULL, NULL,
+ };
+#endif
+ static const GInterfaceInfo implements_iface_info = {
+ (GInterfaceInitFunc) gst_pulsesrc_implements_interface_init,
+ NULL,
+ NULL,
+ };
+ static const GInterfaceInfo mixer_iface_info = {
+ (GInterfaceInitFunc) gst_pulsesrc_mixer_interface_init,
+ NULL,
+ NULL,
+ };
+ static const GInterfaceInfo probe_iface_info = {
+ (GInterfaceInitFunc) gst_pulsesrc_property_probe_interface_init,
+ NULL,
+ NULL,
+ };
+
+#ifdef HAVE_PULSE_1_0
+ g_type_add_interface_static (type, GST_TYPE_STREAM_VOLUME, &svol_iface_info);
+#endif
+ g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
+ &implements_iface_info);
+ g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info);
+ g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
+ &probe_iface_info);
+}
+
+static void
+gst_pulsesrc_base_init (gpointer g_class)
+{
+
+ static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw-int, "
+ "endianness = (int) { " ENDIANNESS " }, "
+ "signed = (boolean) TRUE, "
+ "width = (int) 16, "
+ "depth = (int) 16, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) [ 1, 32 ];"
+ "audio/x-raw-float, "
+ "endianness = (int) { " ENDIANNESS " }, "
+ "width = (int) 32, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) [ 1, 32 ];"
+ "audio/x-raw-int, "
+ "endianness = (int) { " ENDIANNESS " }, "
+ "signed = (boolean) TRUE, "
+ "width = (int) 32, "
+ "depth = (int) 32, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) [ 1, 32 ];"
+ "audio/x-raw-int, "
+ "signed = (boolean) FALSE, "
+ "width = (int) 8, "
+ "depth = (int) 8, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) [ 1, 32 ];"
+ "audio/x-alaw, "
+ "rate = (int) [ 1, MAX], "
+ "channels = (int) [ 1, 32 ];"
+ "audio/x-mulaw, "
+ "rate = (int) [ 1, MAX], " "channels = (int) [ 1, 32 ]")
+ );
+
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details_simple (element_class,
+ "PulseAudio Audio Source",
+ "Source/Audio",
+ "Captures audio from a PulseAudio server", "Lennart Poettering");
+ gst_element_class_add_static_pad_template (element_class, &pad_template);
+}
+
+static void
+gst_pulsesrc_class_init (GstPulseSrcClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstAudioSrcClass *gstaudiosrc_class = GST_AUDIO_SRC_CLASS (klass);
+ GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+ gchar *clientname;
+
+ gobject_class->finalize = gst_pulsesrc_finalize;
+ gobject_class->set_property = gst_pulsesrc_set_property;
+ gobject_class->get_property = gst_pulsesrc_get_property;
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_pulsesrc_change_state);
+
+ gstbasesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_pulsesrc_negotiate);
+
+ gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_pulsesrc_open);
+ gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_pulsesrc_close);
+ gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_pulsesrc_prepare);
+ gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_pulsesrc_unprepare);
+ gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_pulsesrc_read);
+ gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_pulsesrc_delay);
+ gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_pulsesrc_reset);
+
+ /* Overwrite GObject fields */
+ g_object_class_install_property (gobject_class,
+ PROP_SERVER,
+ g_param_spec_string ("server", "Server",
+ "The PulseAudio server to connect to", DEFAULT_SERVER,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_DEVICE,
+ g_param_spec_string ("device", "Device",
+ "The PulseAudio source device to connect to", DEFAULT_DEVICE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class,
+ PROP_DEVICE_NAME,
+ g_param_spec_string ("device-name", "Device name",
+ "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ clientname = gst_pulse_client_name ();
+ /**
+ * GstPulseSrc:client
+ *
+ * The PulseAudio client name to use.
+ *
+ * Since: 0.10.27
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_CLIENT,
+ g_param_spec_string ("client", "Client",
+ "The PulseAudio client_name_to_use", clientname,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ GST_PARAM_MUTABLE_READY));
+ g_free (clientname);
+
+ /**
+ * GstPulseSrc:stream-properties
+ *
+ * List of pulseaudio stream properties. A list of defined properties can be
+ * found in the <ulink href="http://0pointer.de/lennart/projects/pulseaudio/doxygen/proplist_8h.html">pulseaudio api docs</ulink>.
+ *
+ * Below is an example for registering as a music application to pulseaudio.
+ * |[
+ * GstStructure *props;
+ *
+ * props = gst_structure_from_string ("props,media.role=music", NULL);
+ * g_object_set (pulse, "stream-properties", props, NULL);
+ * gst_structure_free (props);
+ * ]|
+ *
+ * Since: 0.10.26
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_STREAM_PROPERTIES,
+ g_param_spec_boxed ("stream-properties", "stream properties",
+ "list of pulseaudio stream properties",
+ GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstPulseSrc:source-output-index
+ *
+ * The index of the PulseAudio source output corresponding to this element.
+ *
+ * Since: 0.10.31
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_SOURCE_OUTPUT_INDEX,
+ g_param_spec_uint ("source-output-index", "source output index",
+ "The index of the PulseAudio source output corresponding to this "
+ "record stream", 0, G_MAXUINT, PA_INVALID_INDEX,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+#ifdef HAVE_PULSE_1_0
+ /**
+ * GstPulseSrc:volume
+ *
+ * The volume of the record stream. Only works when using PulseAudio 1.0 or
+ * later.
+ *
+ * Since: 0.10.36
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_VOLUME, g_param_spec_double ("volume", "Volume",
+ "Linear volume of this stream, 1.0=100%",
+ 0.0, MAX_VOLUME, DEFAULT_VOLUME,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstPulseSrc:mute
+ *
+ * Whether the stream is muted or not. Only works when using PulseAudio 1.0
+ * or later.
+ *
+ * Since: 0.10.36
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_MUTE, g_param_spec_boolean ("mute", "Mute",
+ "Mute state of this stream",
+ DEFAULT_MUTE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
+}
+
+static void
+gst_pulsesrc_init (GstPulseSrc * pulsesrc, GstPulseSrcClass * klass)
+{
+ pulsesrc->server = NULL;
+ pulsesrc->device = NULL;
+ pulsesrc->client_name = gst_pulse_client_name ();
+ pulsesrc->device_description = NULL;
+
+ pulsesrc->context = NULL;
+ pulsesrc->stream = NULL;
+ pulsesrc->source_output_idx = PA_INVALID_INDEX;
+
+ pulsesrc->read_buffer = NULL;
+ pulsesrc->read_buffer_length = 0;
+
+ pa_sample_spec_init (&pulsesrc->sample_spec);
+
+ pulsesrc->operation_success = FALSE;
+ pulsesrc->paused = FALSE;
+ pulsesrc->in_read = FALSE;
+
+#ifdef HAVE_PULSE_1_0
+ pulsesrc->volume = DEFAULT_VOLUME;
+ pulsesrc->volume_set = FALSE;
+
+ pulsesrc->mute = DEFAULT_MUTE;
+ pulsesrc->mute_set = FALSE;
+
+ pulsesrc->notify = 0;
+#endif
+
+ pulsesrc->mixer = NULL;
+
+ pulsesrc->properties = NULL;
+ pulsesrc->proplist = NULL;
+
+ pulsesrc->probe = gst_pulseprobe_new (G_OBJECT (pulsesrc), G_OBJECT_GET_CLASS (pulsesrc), PROP_DEVICE, pulsesrc->server, FALSE, TRUE); /* FALSE for sinks, TRUE for sources */
+
+ /* this should be the default but it isn't yet */
+ gst_base_audio_src_set_slave_method (GST_BASE_AUDIO_SRC (pulsesrc),
+ GST_BASE_AUDIO_SRC_SLAVE_SKEW);
+}
+
+static void
+gst_pulsesrc_destroy_stream (GstPulseSrc * pulsesrc)
+{
+ if (pulsesrc->stream) {
+ pa_stream_disconnect (pulsesrc->stream);
+ pa_stream_unref (pulsesrc->stream);
+ pulsesrc->stream = NULL;
+ pulsesrc->source_output_idx = PA_INVALID_INDEX;
+ g_object_notify (G_OBJECT (pulsesrc), "source-output-index");
+ }
+
+ g_free (pulsesrc->device_description);
+ pulsesrc->device_description = NULL;
+}
+
+static void
+gst_pulsesrc_destroy_context (GstPulseSrc * pulsesrc)
+{
+
+ gst_pulsesrc_destroy_stream (pulsesrc);
+
+ if (pulsesrc->context) {
+ pa_context_disconnect (pulsesrc->context);
+
+ /* Make sure we don't get any further callbacks */
+ pa_context_set_state_callback (pulsesrc->context, NULL, NULL);
+#ifdef HAVE_PULSE_1_0
+ pa_context_set_subscribe_callback (pulsesrc->context, NULL, NULL);
+#endif
+
+ pa_context_unref (pulsesrc->context);
+
+ pulsesrc->context = NULL;
+ }
+}
+
+static void
+gst_pulsesrc_finalize (GObject * object)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object);
+
+ g_free (pulsesrc->server);
+ g_free (pulsesrc->device);
+ g_free (pulsesrc->client_name);
+
+ if (pulsesrc->properties)
+ gst_structure_free (pulsesrc->properties);
+ if (pulsesrc->proplist)
+ pa_proplist_free (pulsesrc->proplist);
+
+ if (pulsesrc->mixer) {
+ gst_pulsemixer_ctrl_free (pulsesrc->mixer);
+ pulsesrc->mixer = NULL;
+ }
+
+ if (pulsesrc->probe) {
+ gst_pulseprobe_free (pulsesrc->probe);
+ pulsesrc->probe = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+#define CONTEXT_OK(c) ((c) && PA_CONTEXT_IS_GOOD (pa_context_get_state ((c))))
+#define STREAM_OK(s) ((s) && PA_STREAM_IS_GOOD (pa_stream_get_state ((s))))
+
+static gboolean
+gst_pulsesrc_is_dead (GstPulseSrc * pulsesrc, gboolean check_stream)
+{
+ if (!CONTEXT_OK (pulsesrc->context))
+ goto error;
+
+ if (check_stream && !STREAM_OK (pulsesrc->stream))
+ goto error;
+
+ return FALSE;
+
+error:
+ {
+ const gchar *err_str = pulsesrc->context ?
+ pa_strerror (pa_context_errno (pulsesrc->context)) : NULL;
+ GST_ELEMENT_ERROR ((pulsesrc), RESOURCE, FAILED, ("Disconnected: %s",
+ err_str), (NULL));
+ return TRUE;
+ }
+}
+
+static void
+gst_pulsesrc_source_info_cb (pa_context * c, const pa_source_info * i, int eol,
+ void *userdata)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
+
+ if (!i)
+ goto done;
+
+ g_free (pulsesrc->device_description);
+ pulsesrc->device_description = g_strdup (i->description);
+
+done:
+ pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+}
+
+static gchar *
+gst_pulsesrc_device_description (GstPulseSrc * pulsesrc)
+{
+ pa_operation *o = NULL;
+ gchar *t;
+
+ if (!pulsesrc->mainloop)
+ goto no_mainloop;
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+ if (!(o = pa_context_get_source_info_by_name (pulsesrc->context,
+ pulsesrc->device, gst_pulsesrc_source_info_cb, pulsesrc))) {
+
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("pa_stream_get_source_info() failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock;
+ }
+
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+
+ if (gst_pulsesrc_is_dead (pulsesrc, FALSE))
+ goto unlock;
+
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ }
+
+unlock:
+
+ if (o)
+ pa_operation_unref (o);
+
+ t = g_strdup (pulsesrc->device_description);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ return t;
+
+no_mainloop:
+ {
+ GST_DEBUG_OBJECT (pulsesrc, "have no mainloop");
+ return NULL;
+ }
+}
+
+#ifdef HAVE_PULSE_1_0
+static void
+gst_pulsesrc_source_output_info_cb (pa_context * c,
+ const pa_source_output_info * i, int eol, void *userdata)
+{
+ GstPulseSrc *psrc;
+
+ psrc = GST_PULSESRC_CAST (userdata);
+
+ if (!i)
+ goto done;
+
+ /* If the index doesn't match our current stream,
+ * it implies we just recreated the stream (caps change)
+ */
+ if (i->index == psrc->source_output_idx) {
+ psrc->volume = pa_sw_volume_to_linear (pa_cvolume_max (&i->volume));
+ psrc->mute = i->mute;
+ }
+
+done:
+ pa_threaded_mainloop_signal (psrc->mainloop, 0);
+}
+
+static gdouble
+gst_pulsesrc_get_stream_volume (GstPulseSrc * pulsesrc)
+{
+ pa_operation *o = NULL;
+ gdouble v;
+
+ if (!pulsesrc->mainloop)
+ goto no_mainloop;
+
+ if (pulsesrc->source_output_idx == PA_INVALID_INDEX)
+ goto no_index;
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+ if (!(o = pa_context_get_source_output_info (pulsesrc->context,
+ pulsesrc->source_output_idx, gst_pulsesrc_source_output_info_cb,
+ pulsesrc)))
+ goto info_failed;
+
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
+ goto unlock;
+ }
+
+unlock:
+ v = pulsesrc->volume;
+
+ if (o)
+ pa_operation_unref (o);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ if (v > MAX_VOLUME) {
+ GST_WARNING_OBJECT (pulsesrc, "Clipped volume from %f to %f", v,
+ MAX_VOLUME);
+ v = MAX_VOLUME;
+ }
+
+ return v;
+
+ /* ERRORS */
+no_mainloop:
+ {
+ v = pulsesrc->volume;
+ GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
+ return v;
+ }
+no_index:
+ {
+ v = pulsesrc->volume;
+ GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
+ return v;
+ }
+info_failed:
+ {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("pa_context_get_source_output_info() failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock;
+ }
+}
+
+static gboolean
+gst_pulsesrc_get_stream_mute (GstPulseSrc * pulsesrc)
+{
+ pa_operation *o = NULL;
+ gboolean mute;
+
+ if (!pulsesrc->mainloop)
+ goto no_mainloop;
+
+ if (pulsesrc->source_output_idx == PA_INVALID_INDEX)
+ goto no_index;
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+ if (!(o = pa_context_get_source_output_info (pulsesrc->context,
+ pulsesrc->source_output_idx, gst_pulsesrc_source_output_info_cb,
+ pulsesrc)))
+ goto info_failed;
+
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
+ goto unlock;
+ }
+
+unlock:
+ mute = pulsesrc->mute;
+
+ if (o)
+ pa_operation_unref (o);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ return mute;
+
+ /* ERRORS */
+no_mainloop:
+ {
+ mute = pulsesrc->mute;
+ GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
+ return mute;
+ }
+no_index:
+ {
+ mute = pulsesrc->mute;
+ GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
+ return mute;
+ }
+info_failed:
+ {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("pa_context_get_source_output_info() failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock;
+ }
+}
+
+static void
+gst_pulsesrc_set_stream_volume (GstPulseSrc * pulsesrc, gdouble volume)
+{
+ pa_cvolume v;
+ pa_operation *o = NULL;
+
+ if (!pulsesrc->mainloop)
+ goto no_mainloop;
+
+ if (!pulsesrc->source_output_idx)
+ goto no_index;
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+ GST_DEBUG_OBJECT (pulsesrc, "setting volume to %f", volume);
+
+ gst_pulse_cvolume_from_linear (&v, pulsesrc->sample_spec.channels, volume);
+
+ if (!(o = pa_context_set_source_output_volume (pulsesrc->context,
+ pulsesrc->source_output_idx, &v, NULL, NULL)))
+ goto volume_failed;
+
+ /* We don't really care about the result of this call */
+unlock:
+
+ if (o)
+ pa_operation_unref (o);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ return;
+
+ /* ERRORS */
+no_mainloop:
+ {
+ pulsesrc->volume = volume;
+ pulsesrc->volume_set = TRUE;
+ GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
+ return;
+ }
+no_index:
+ {
+ pulsesrc->volume = volume;
+ pulsesrc->volume_set = TRUE;
+ GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
+ return;
+ }
+volume_failed:
+ {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("pa_stream_set_source_output_volume() failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock;
+ }
+}
+
+static void
+gst_pulsesrc_set_stream_mute (GstPulseSrc * pulsesrc, gboolean mute)
+{
+ pa_operation *o = NULL;
+
+ if (!pulsesrc->mainloop)
+ goto no_mainloop;
+
+ if (!pulsesrc->source_output_idx)
+ goto no_index;
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+ GST_DEBUG_OBJECT (pulsesrc, "setting mute state to %d", mute);
+
+ if (!(o = pa_context_set_source_output_mute (pulsesrc->context,
+ pulsesrc->source_output_idx, mute, NULL, NULL)))
+ goto mute_failed;
+
+ /* We don't really care about the result of this call */
+unlock:
+
+ if (o)
+ pa_operation_unref (o);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ return;
+
+ /* ERRORS */
+no_mainloop:
+ {
+ pulsesrc->mute = mute;
+ pulsesrc->mute_set = TRUE;
+ GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop");
+ return;
+ }
+no_index:
+ {
+ pulsesrc->mute = mute;
+ pulsesrc->mute_set = TRUE;
+ GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index");
+ return;
+ }
+mute_failed:
+ {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("pa_stream_set_source_output_mute() failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock;
+ }
+}
+#endif
+
+static void
+gst_pulsesrc_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object);
+
+ switch (prop_id) {
+ case PROP_SERVER:
+ g_free (pulsesrc->server);
+ pulsesrc->server = g_value_dup_string (value);
+ if (pulsesrc->probe)
+ gst_pulseprobe_set_server (pulsesrc->probe, pulsesrc->server);
+ break;
+ case PROP_DEVICE:
+ g_free (pulsesrc->device);
+ pulsesrc->device = g_value_dup_string (value);
+ break;
+ case PROP_CLIENT:
+ g_free (pulsesrc->client_name);
+ if (!g_value_get_string (value)) {
+ GST_WARNING_OBJECT (pulsesrc,
+ "Empty PulseAudio client name not allowed. Resetting to default value");
+ pulsesrc->client_name = gst_pulse_client_name ();
+ } else
+ pulsesrc->client_name = g_value_dup_string (value);
+ break;
+ case PROP_STREAM_PROPERTIES:
+ if (pulsesrc->properties)
+ gst_structure_free (pulsesrc->properties);
+ pulsesrc->properties =
+ gst_structure_copy (gst_value_get_structure (value));
+ if (pulsesrc->proplist)
+ pa_proplist_free (pulsesrc->proplist);
+ pulsesrc->proplist = gst_pulse_make_proplist (pulsesrc->properties);
+ break;
+#ifdef HAVE_PULSE_1_0
+ case PROP_VOLUME:
+ gst_pulsesrc_set_stream_volume (pulsesrc, g_value_get_double (value));
+ break;
+ case PROP_MUTE:
+ gst_pulsesrc_set_stream_mute (pulsesrc, g_value_get_boolean (value));
+ break;
+#endif
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_pulsesrc_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object);
+
+ switch (prop_id) {
+ case PROP_SERVER:
+ g_value_set_string (value, pulsesrc->server);
+ break;
+ case PROP_DEVICE:
+ g_value_set_string (value, pulsesrc->device);
+ break;
+ case PROP_DEVICE_NAME:
+ g_value_take_string (value, gst_pulsesrc_device_description (pulsesrc));
+ break;
+ case PROP_CLIENT:
+ g_value_set_string (value, pulsesrc->client_name);
+ break;
+ case PROP_STREAM_PROPERTIES:
+ gst_value_set_structure (value, pulsesrc->properties);
+ break;
+ case PROP_SOURCE_OUTPUT_INDEX:
+ g_value_set_uint (value, pulsesrc->source_output_idx);
+ break;
+#ifdef HAVE_PULSE_1_0
+ case PROP_VOLUME:
+ g_value_set_double (value, gst_pulsesrc_get_stream_volume (pulsesrc));
+ break;
+ case PROP_MUTE:
+ g_value_set_boolean (value, gst_pulsesrc_get_stream_mute (pulsesrc));
+ break;
+#endif
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_pulsesrc_context_state_cb (pa_context * c, void *userdata)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
+
+ switch (pa_context_get_state (c)) {
+ case PA_CONTEXT_READY:
+ case PA_CONTEXT_TERMINATED:
+ case PA_CONTEXT_FAILED:
+ pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+ break;
+
+ case PA_CONTEXT_UNCONNECTED:
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ break;
+ }
+}
+
+static void
+gst_pulsesrc_stream_state_cb (pa_stream * s, void *userdata)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
+
+ switch (pa_stream_get_state (s)) {
+
+ case PA_STREAM_READY:
+ case PA_STREAM_FAILED:
+ case PA_STREAM_TERMINATED:
+ pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+ break;
+
+ case PA_STREAM_UNCONNECTED:
+ case PA_STREAM_CREATING:
+ break;
+ }
+}
+
+static void
+gst_pulsesrc_stream_request_cb (pa_stream * s, size_t length, void *userdata)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
+
+ GST_LOG_OBJECT (pulsesrc, "got request for length %" G_GSIZE_FORMAT, length);
+
+ if (pulsesrc->in_read) {
+ /* only signal when reading */
+ pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+ }
+}
+
+static void
+gst_pulsesrc_stream_latency_update_cb (pa_stream * s, void *userdata)
+{
+ const pa_timing_info *info;
+ pa_usec_t source_usec;
+
+ info = pa_stream_get_timing_info (s);
+
+ if (!info) {
+ GST_LOG_OBJECT (GST_PULSESRC_CAST (userdata),
+ "latency update (information unknown)");
+ return;
+ }
+ source_usec = info->configured_source_usec;
+
+ GST_LOG_OBJECT (GST_PULSESRC_CAST (userdata),
+ "latency_update, %" G_GUINT64_FORMAT ", %d:%" G_GINT64_FORMAT ", %d:%"
+ G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT,
+ GST_TIMEVAL_TO_TIME (info->timestamp), info->write_index_corrupt,
+ info->write_index, info->read_index_corrupt, info->read_index,
+ info->source_usec, source_usec);
+}
+
+static void
+gst_pulsesrc_stream_underflow_cb (pa_stream * s, void *userdata)
+{
+ GST_WARNING_OBJECT (GST_PULSESRC_CAST (userdata), "Got underflow");
+}
+
+static void
+gst_pulsesrc_stream_overflow_cb (pa_stream * s, void *userdata)
+{
+ GST_WARNING_OBJECT (GST_PULSESRC_CAST (userdata), "Got overflow");
+}
+
+#ifdef HAVE_PULSE_1_0
+static void
+gst_pulsesrc_context_subscribe_cb (pa_context * c,
+ pa_subscription_event_type_t t, uint32_t idx, void *userdata)
+{
+ GstPulseSrc *psrc = GST_PULSESRC (userdata);
+
+ if (t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT | PA_SUBSCRIPTION_EVENT_CHANGE)
+ && t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT | PA_SUBSCRIPTION_EVENT_NEW))
+ return;
+
+ if (idx != psrc->source_output_idx)
+ return;
+
+ /* Actually this event is also triggered when other properties of the stream
+ * change that are unrelated to the volume. However it is probably cheaper to
+ * signal the change here and check for the volume when the GObject property
+ * is read instead of querying it always. */
+
+ /* inform streaming thread to notify */
+ g_atomic_int_compare_and_exchange (&psrc->notify, 0, 1);
+}
+#endif
+
+static gboolean
+gst_pulsesrc_open (GstAudioSrc * asrc)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+ g_assert (!pulsesrc->context);
+ g_assert (!pulsesrc->stream);
+
+ GST_DEBUG_OBJECT (pulsesrc, "opening device");
+
+ if (!(pulsesrc->context =
+ pa_context_new (pa_threaded_mainloop_get_api (pulsesrc->mainloop),
+ pulsesrc->client_name))) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to create context"),
+ (NULL));
+ goto unlock_and_fail;
+ }
+
+ pa_context_set_state_callback (pulsesrc->context,
+ gst_pulsesrc_context_state_cb, pulsesrc);
+#ifdef HAVE_PULSE_1_0
+ pa_context_set_subscribe_callback (pulsesrc->context,
+ gst_pulsesrc_context_subscribe_cb, pulsesrc);
+#endif
+
+ GST_DEBUG_OBJECT (pulsesrc, "connect to server %s",
+ GST_STR_NULL (pulsesrc->server));
+
+ if (pa_context_connect (pulsesrc->context, pulsesrc->server, 0, NULL) < 0) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+
+ for (;;) {
+ pa_context_state_t state;
+
+ state = pa_context_get_state (pulsesrc->context);
+
+ if (!PA_CONTEXT_IS_GOOD (state)) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+
+ if (state == PA_CONTEXT_READY)
+ break;
+
+ /* Wait until the context is ready */
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ }
+ GST_DEBUG_OBJECT (pulsesrc, "connected");
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ return TRUE;
+
+ /* ERRORS */
+unlock_and_fail:
+ {
+ gst_pulsesrc_destroy_context (pulsesrc);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_pulsesrc_close (GstAudioSrc * asrc)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+ gst_pulsesrc_destroy_context (pulsesrc);
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ return TRUE;
+}
+
+static gboolean
+gst_pulsesrc_unprepare (GstAudioSrc * asrc)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+ gst_pulsesrc_destroy_stream (pulsesrc);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ pulsesrc->read_buffer = NULL;
+ pulsesrc->read_buffer_length = 0;
+
+ return TRUE;
+}
+
+static guint
+gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data, guint length)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+ size_t sum = 0;
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+ pulsesrc->in_read = TRUE;
+
+#ifdef HAVE_PULSE_1_0
+ if (g_atomic_int_compare_and_exchange (&pulsesrc->notify, 1, 0)) {
+ g_object_notify (G_OBJECT (pulsesrc), "volume");
+ g_object_notify (G_OBJECT (pulsesrc), "mute");
+ }
+#endif
+
+ if (pulsesrc->paused)
+ goto was_paused;
+
+ while (length > 0) {
+ size_t l;
+
+ GST_LOG_OBJECT (pulsesrc, "reading %u bytes", length);
+
+ /*check if we have a leftover buffer */
+ if (!pulsesrc->read_buffer) {
+ for (;;) {
+ if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
+ goto unlock_and_fail;
+
+ /* read all available data, we keep a pointer to the data and the length
+ * and take from it what we need. */
+ if (pa_stream_peek (pulsesrc->stream, &pulsesrc->read_buffer,
+ &pulsesrc->read_buffer_length) < 0)
+ goto peek_failed;
+
+ GST_LOG_OBJECT (pulsesrc, "have data of %" G_GSIZE_FORMAT " bytes",
+ pulsesrc->read_buffer_length);
+
+ /* if we have data, process if */
+ if (pulsesrc->read_buffer && pulsesrc->read_buffer_length)
+ break;
+
+ /* now wait for more data to become available */
+ GST_LOG_OBJECT (pulsesrc, "waiting for data");
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
+
+ if (pulsesrc->paused)
+ goto was_paused;
+ }
+ }
+
+ l = pulsesrc->read_buffer_length >
+ length ? length : pulsesrc->read_buffer_length;
+
+ memcpy (data, pulsesrc->read_buffer, l);
+
+ pulsesrc->read_buffer = (const guint8 *) pulsesrc->read_buffer + l;
+ pulsesrc->read_buffer_length -= l;
+
+ data = (guint8 *) data + l;
+ length -= l;
+ sum += l;
+
+ if (pulsesrc->read_buffer_length <= 0) {
+ /* we copied all of the data, drop it now */
+ if (pa_stream_drop (pulsesrc->stream) < 0)
+ goto drop_failed;
+
+ /* reset pointer to data */
+ pulsesrc->read_buffer = NULL;
+ pulsesrc->read_buffer_length = 0;
+ }
+ }
+
+ pulsesrc->in_read = FALSE;
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ return sum;
+
+ /* ERRORS */
+was_paused:
+ {
+ GST_LOG_OBJECT (pulsesrc, "we are paused");
+ goto unlock_and_fail;
+ }
+peek_failed:
+ {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("pa_stream_peek() failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+drop_failed:
+ {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("pa_stream_drop() failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+unlock_and_fail:
+ {
+ pulsesrc->in_read = FALSE;
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ return (guint) - 1;
+ }
+}
+
+/* return the delay in samples */
+static guint
+gst_pulsesrc_delay (GstAudioSrc * asrc)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+ pa_usec_t t;
+ int negative, res;
+ guint result;
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+ if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
+ goto server_dead;
+
+ /* get the latency, this can fail when we don't have a latency update yet.
+ * We don't want to wait for latency updates here but we just return 0. */
+ res = pa_stream_get_latency (pulsesrc->stream, &t, &negative);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ if (res < 0) {
+ GST_DEBUG_OBJECT (pulsesrc, "could not get latency");
+ result = 0;
+ } else {
+ if (negative)
+ result = 0;
+ else
+ result = (guint) ((t * pulsesrc->sample_spec.rate) / 1000000LL);
+ }
+ return result;
+
+ /* ERRORS */
+server_dead:
+ {
+ GST_DEBUG_OBJECT (pulsesrc, "the server is dead");
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+ return 0;
+ }
+}
+
+static gboolean
+gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps * caps)
+{
+ pa_channel_map channel_map;
+ GstStructure *s;
+ gboolean need_channel_layout = FALSE;
+ GstRingBufferSpec spec;
+ const gchar *name;
+
+ memset (&spec, 0, sizeof (GstRingBufferSpec));
+ spec.latency_time = GST_SECOND;
+ if (!gst_ring_buffer_parse_caps (&spec, caps)) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS,
+ ("Can't parse caps."), (NULL));
+ goto fail;
+ }
+ /* Keep the refcount of the caps at 1 to make them writable */
+ gst_caps_unref (spec.caps);
+
+ if (!gst_pulse_fill_sample_spec (&spec, &pulsesrc->sample_spec)) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS,
+ ("Invalid sample specification."), (NULL));
+ goto fail;
+ }
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+ if (!pulsesrc->context) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Bad context"), (NULL));
+ goto unlock_and_fail;
+ }
+
+ s = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_has_field (s, "channel-layout") ||
+ !gst_pulse_gst_to_channel_map (&channel_map, &spec)) {
+ if (spec.channels == 1)
+ pa_channel_map_init_mono (&channel_map);
+ else if (spec.channels == 2)
+ pa_channel_map_init_stereo (&channel_map);
+ else
+ need_channel_layout = TRUE;
+ }
+
+ name = "Record Stream";
+ if (pulsesrc->proplist) {
+ if (!(pulsesrc->stream = pa_stream_new_with_proplist (pulsesrc->context,
+ name, &pulsesrc->sample_spec,
+ (need_channel_layout) ? NULL : &channel_map,
+ pulsesrc->proplist))) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("Failed to create stream: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+ } else if (!(pulsesrc->stream = pa_stream_new (pulsesrc->context,
+ name, &pulsesrc->sample_spec,
+ (need_channel_layout) ? NULL : &channel_map))) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("Failed to create stream: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+
+ if (need_channel_layout) {
+ const pa_channel_map *m = pa_stream_get_channel_map (pulsesrc->stream);
+
+ gst_pulse_channel_map_to_gst (m, &spec);
+ caps = spec.caps;
+ }
+
+ GST_DEBUG_OBJECT (pulsesrc, "Caps are %" GST_PTR_FORMAT, caps);
+
+ pa_stream_set_state_callback (pulsesrc->stream, gst_pulsesrc_stream_state_cb,
+ pulsesrc);
+ pa_stream_set_read_callback (pulsesrc->stream, gst_pulsesrc_stream_request_cb,
+ pulsesrc);
+ pa_stream_set_underflow_callback (pulsesrc->stream,
+ gst_pulsesrc_stream_underflow_cb, pulsesrc);
+ pa_stream_set_overflow_callback (pulsesrc->stream,
+ gst_pulsesrc_stream_overflow_cb, pulsesrc);
+ pa_stream_set_latency_update_callback (pulsesrc->stream,
+ gst_pulsesrc_stream_latency_update_cb, pulsesrc);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ return TRUE;
+
+unlock_and_fail:
+ gst_pulsesrc_destroy_stream (pulsesrc);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+fail:
+ return FALSE;
+}
+
+/* This is essentially gst_base_src_negotiate_default() but the caps
+ * are guaranteed to have a channel layout for > 2 channels
+ */
+static gboolean
+gst_pulsesrc_negotiate (GstBaseSrc * basesrc)
+{
+ GstCaps *thiscaps;
+ GstCaps *caps = NULL;
+ GstCaps *peercaps = NULL;
+ gboolean result = FALSE;
+
+ /* first see what is possible on our source pad */
+ thiscaps = gst_pad_get_caps_reffed (GST_BASE_SRC_PAD (basesrc));
+ GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps);
+ /* nothing or anything is allowed, we're done */
+ if (thiscaps == NULL || gst_caps_is_any (thiscaps))
+ goto no_nego_needed;
+
+ /* get the peer caps */
+ peercaps = gst_pad_peer_get_caps_reffed (GST_BASE_SRC_PAD (basesrc));
+ GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps);
+ if (peercaps) {
+ /* get intersection */
+ caps = gst_caps_intersect (thiscaps, peercaps);
+ GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, caps);
+ gst_caps_unref (thiscaps);
+ gst_caps_unref (peercaps);
+ } else {
+ /* no peer, work with our own caps then */
+ caps = thiscaps;
+ }
+ if (caps) {
+ /* take first (and best, since they are sorted) possibility */
+ caps = gst_caps_make_writable (caps);
+ gst_caps_truncate (caps);
+
+ /* now fixate */
+ if (!gst_caps_is_empty (caps)) {
+ gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
+ GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps);
+
+ if (gst_caps_is_any (caps)) {
+ /* hmm, still anything, so element can do anything and
+ * nego is not needed */
+ result = TRUE;
+ } else if (gst_caps_is_fixed (caps)) {
+ /* yay, fixed caps, use those then */
+ result = gst_pulsesrc_create_stream (GST_PULSESRC_CAST (basesrc), caps);
+ if (result)
+ result = gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
+ }
+ }
+ gst_caps_unref (caps);
+ }
+ return result;
+
+no_nego_needed:
+ {
+ GST_DEBUG_OBJECT (basesrc, "no negotiation needed");
+ if (thiscaps)
+ gst_caps_unref (thiscaps);
+ return TRUE;
+ }
+}
+
+static gboolean
+gst_pulsesrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
+{
+ pa_buffer_attr wanted;
+ const pa_buffer_attr *actual;
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+ pa_stream_flags_t flags;
+#ifdef HAVE_PULSE_1_0
+ pa_operation *o;
+#endif
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+#ifdef HAVE_PULSE_1_0
+ /* enable event notifications */
+ GST_LOG_OBJECT (pulsesrc, "subscribing to context events");
+ if (!(o = pa_context_subscribe (pulsesrc->context,
+ PA_SUBSCRIPTION_MASK_SINK_INPUT, NULL, NULL))) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("pa_context_subscribe() failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+
+ pa_operation_unref (o);
+#endif
+
+ wanted.maxlength = -1;
+ wanted.tlength = -1;
+ wanted.prebuf = 0;
+ wanted.minreq = -1;
+ wanted.fragsize = spec->segsize;
+
+ GST_INFO_OBJECT (pulsesrc, "maxlength: %d", wanted.maxlength);
+ GST_INFO_OBJECT (pulsesrc, "tlength: %d", wanted.tlength);
+ GST_INFO_OBJECT (pulsesrc, "prebuf: %d", wanted.prebuf);
+ GST_INFO_OBJECT (pulsesrc, "minreq: %d", wanted.minreq);
+ GST_INFO_OBJECT (pulsesrc, "fragsize: %d", wanted.fragsize);
+
+ flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
+ PA_STREAM_NOT_MONOTONIC | PA_STREAM_ADJUST_LATENCY |
+ PA_STREAM_START_CORKED;
+
+#ifdef HAVE_PULSE_1_0
+ if (pulsesrc->mute_set && pulsesrc->mute)
+ flags |= PA_STREAM_START_MUTED;
+#endif
+
+ if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &wanted,
+ flags) < 0) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("Failed to connect stream: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+
+ pulsesrc->corked = TRUE;
+
+ for (;;) {
+ pa_stream_state_t state;
+
+ state = pa_stream_get_state (pulsesrc->stream);
+
+ if (!PA_STREAM_IS_GOOD (state)) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("Failed to connect stream: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+
+ if (state == PA_STREAM_READY)
+ break;
+
+ /* Wait until the stream is ready */
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ }
+
+ /* store the source output index so it can be accessed via a property */
+ pulsesrc->source_output_idx = pa_stream_get_index (pulsesrc->stream);
+ g_object_notify (G_OBJECT (pulsesrc), "source-output-index");
+
+#ifdef HAVE_PULSE_1_0
+ if (pulsesrc->volume_set) {
+ gst_pulsesrc_set_stream_volume (pulsesrc, pulsesrc->volume);
+ pulsesrc->volume_set = FALSE;
+ }
+#endif
+
+ /* get the actual buffering properties now */
+ actual = pa_stream_get_buffer_attr (pulsesrc->stream);
+
+ GST_INFO_OBJECT (pulsesrc, "maxlength: %d", actual->maxlength);
+ GST_INFO_OBJECT (pulsesrc, "tlength: %d (wanted: %d)",
+ actual->tlength, wanted.tlength);
+ GST_INFO_OBJECT (pulsesrc, "prebuf: %d", actual->prebuf);
+ GST_INFO_OBJECT (pulsesrc, "minreq: %d (wanted %d)", actual->minreq,
+ wanted.minreq);
+ GST_INFO_OBJECT (pulsesrc, "fragsize: %d (wanted %d)",
+ actual->fragsize, wanted.fragsize);
+
+ if (actual->fragsize >= wanted.fragsize) {
+ spec->segsize = actual->fragsize;
+ } else {
+ spec->segsize = actual->fragsize * (wanted.fragsize / actual->fragsize);
+ }
+ spec->segtotal = actual->maxlength / spec->segsize;
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ return TRUE;
+
+unlock_and_fail:
+ {
+ gst_pulsesrc_destroy_stream (pulsesrc);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+ return FALSE;
+ }
+}
+
+static void
+gst_pulsesrc_success_cb (pa_stream * s, int success, void *userdata)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata);
+
+ pulsesrc->operation_success = ! !success;
+ pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+}
+
+static void
+gst_pulsesrc_reset (GstAudioSrc * asrc)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
+ pa_operation *o = NULL;
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+ GST_DEBUG_OBJECT (pulsesrc, "reset");
+
+ if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
+ goto unlock_and_fail;
+
+ if (!(o =
+ pa_stream_flush (pulsesrc->stream, gst_pulsesrc_success_cb,
+ pulsesrc))) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("pa_stream_flush() failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+
+ pulsesrc->paused = TRUE;
+ /* Inform anyone waiting in _write() call that it shall wakeup */
+ if (pulsesrc->in_read) {
+ pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+ }
+
+ pulsesrc->operation_success = FALSE;
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+
+ if (gst_pulsesrc_is_dead (pulsesrc, TRUE))
+ goto unlock_and_fail;
+
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ }
+
+ if (!pulsesrc->operation_success) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Flush failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+
+unlock_and_fail:
+
+ if (o) {
+ pa_operation_cancel (o);
+ pa_operation_unref (o);
+ }
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+}
+
+/* update the corked state of a stream, must be called with the mainloop
+ * lock */
+static gboolean
+gst_pulsesrc_set_corked (GstPulseSrc * psrc, gboolean corked, gboolean wait)
+{
+ pa_operation *o = NULL;
+ gboolean res = FALSE;
+
+ GST_DEBUG_OBJECT (psrc, "setting corked state to %d", corked);
+ if (psrc->corked != corked) {
+ if (!(o = pa_stream_cork (psrc->stream, corked,
+ gst_pulsesrc_success_cb, psrc)))
+ goto cork_failed;
+
+ while (wait && pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+ pa_threaded_mainloop_wait (psrc->mainloop);
+ if (gst_pulsesrc_is_dead (psrc, TRUE))
+ goto server_dead;
+ }
+ psrc->corked = corked;
+ } else {
+ GST_DEBUG_OBJECT (psrc, "skipping, already in requested state");
+ }
+ res = TRUE;
+
+cleanup:
+ if (o)
+ pa_operation_unref (o);
+
+ return res;
+
+ /* ERRORS */
+server_dead:
+ {
+ GST_DEBUG_OBJECT (psrc, "the server is dead");
+ goto cleanup;
+ }
+cork_failed:
+ {
+ GST_ELEMENT_ERROR (psrc, RESOURCE, FAILED,
+ ("pa_stream_cork() failed: %s",
+ pa_strerror (pa_context_errno (psrc->context))), (NULL));
+ goto cleanup;
+ }
+}
+
+/* start/resume playback ASAP */
+static gboolean
+gst_pulsesrc_play (GstPulseSrc * psrc)
+{
+ pa_threaded_mainloop_lock (psrc->mainloop);
+ GST_DEBUG_OBJECT (psrc, "playing");
+ psrc->paused = FALSE;
+ gst_pulsesrc_set_corked (psrc, FALSE, FALSE);
+ pa_threaded_mainloop_unlock (psrc->mainloop);
+
+ return TRUE;
+}
+
+/* pause/stop playback ASAP */
+static gboolean
+gst_pulsesrc_pause (GstPulseSrc * psrc)
+{
+ pa_threaded_mainloop_lock (psrc->mainloop);
+ GST_DEBUG_OBJECT (psrc, "pausing");
+ /* make sure the commit method stops writing */
+ psrc->paused = TRUE;
+ if (psrc->in_read) {
+ /* we are waiting in a read, signal */
+ GST_DEBUG_OBJECT (psrc, "signal read");
+ pa_threaded_mainloop_signal (psrc->mainloop, 0);
+ }
+ pa_threaded_mainloop_unlock (psrc->mainloop);
+
+ return TRUE;
+}
+
+static GstStateChangeReturn
+gst_pulsesrc_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstPulseSrc *this = GST_PULSESRC_CAST (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!(this->mainloop = pa_threaded_mainloop_new ()))
+ goto mainloop_failed;
+ if (pa_threaded_mainloop_start (this->mainloop) < 0) {
+ pa_threaded_mainloop_free (this->mainloop);
+ this->mainloop = NULL;
+ goto mainloop_start_failed;
+ }
+
+ if (!this->mixer)
+ this->mixer =
+ gst_pulsemixer_ctrl_new (G_OBJECT (this), this->server,
+ this->device, GST_PULSEMIXER_SOURCE);
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ /* uncork and start recording */
+ gst_pulsesrc_play (this);
+ break;
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ /* stop recording ASAP by corking */
+ pa_threaded_mainloop_lock (this->mainloop);
+ GST_DEBUG_OBJECT (this, "corking");
+ gst_pulsesrc_set_corked (this, TRUE, FALSE);
+ pa_threaded_mainloop_unlock (this->mainloop);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ /* now make sure we get out of the _read method */
+ gst_pulsesrc_pause (this);
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ if (this->mixer) {
+ gst_pulsemixer_ctrl_free (this->mixer);
+ this->mixer = NULL;
+ }
+
+ if (this->mainloop)
+ pa_threaded_mainloop_stop (this->mainloop);
+
+ gst_pulsesrc_destroy_context (this);
+
+ if (this->mainloop) {
+ pa_threaded_mainloop_free (this->mainloop);
+ this->mainloop = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+
+ /* ERRORS */
+mainloop_failed:
+ {
+ GST_ELEMENT_ERROR (this, RESOURCE, FAILED,
+ ("pa_threaded_mainloop_new() failed"), (NULL));
+ return GST_STATE_CHANGE_FAILURE;
+ }
+mainloop_start_failed:
+ {
+ GST_ELEMENT_ERROR (this, RESOURCE, FAILED,
+ ("pa_threaded_mainloop_start() failed"), (NULL));
+ return GST_STATE_CHANGE_FAILURE;
+ }
+}
diff --git a/ext/pulse/pulsesrc.h b/ext/pulse/pulsesrc.h
new file mode 100644
index 0000000..655417f
--- /dev/null
+++ b/ext/pulse/pulsesrc.h
@@ -0,0 +1,102 @@
+/*-*- Mode: C; c-basic-offset: 2 -*-*/
+
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifndef __GST_PULSESRC_H__
+#define __GST_PULSESRC_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosrc.h>
+
+#include <pulse/pulseaudio.h>
+#include <pulse/thread-mainloop.h>
+
+#include "pulsemixerctrl.h"
+#include "pulseprobe.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PULSESRC \
+ (gst_pulsesrc_get_type())
+#define GST_PULSESRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PULSESRC,GstPulseSrc))
+#define GST_PULSESRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PULSESRC,GstPulseSrcClass))
+#define GST_IS_PULSESRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PULSESRC))
+#define GST_IS_PULSESRC_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PULSESRC))
+#define GST_PULSESRC_CAST(obj) \
+ ((GstPulseSrc *)(obj))
+
+typedef struct _GstPulseSrc GstPulseSrc;
+typedef struct _GstPulseSrcClass GstPulseSrcClass;
+
+struct _GstPulseSrc
+{
+ GstAudioSrc src;
+
+ gchar *server, *device, *client_name;
+
+ pa_threaded_mainloop *mainloop;
+
+ pa_context *context;
+ pa_stream *stream;
+ guint32 source_output_idx;
+
+ pa_sample_spec sample_spec;
+
+ const void *read_buffer;
+ size_t read_buffer_length;
+
+ gchar *device_description;
+ GstPulseMixerCtrl *mixer;
+ GstPulseProbe *probe;
+
+#ifdef HAVE_PULSE_1_0
+ gdouble volume;
+ gboolean volume_set:1;
+ gboolean mute:1;
+ gboolean mute_set:1;
+
+ gint notify; /* atomic */
+#endif
+
+ gboolean corked:1;
+ gboolean operation_success:1;
+ gboolean paused:1;
+ gboolean in_read:1;
+
+ GstStructure *properties;
+ pa_proplist *proplist;
+};
+
+struct _GstPulseSrcClass
+{
+ GstAudioSrcClass parent_class;
+};
+
+GType gst_pulsesrc_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_PULSESRC_H__ */
diff --git a/ext/pulse/pulseutil.c b/ext/pulse/pulseutil.c
new file mode 100644
index 0000000..0d8af79
--- /dev/null
+++ b/ext/pulse/pulseutil.c
@@ -0,0 +1,337 @@
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pulseutil.h"
+#include <gst/audio/multichannel.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> /* getpid on UNIX */
+#endif
+#ifdef HAVE_PROCESS_H
+# include <process.h> /* getpid on win32 */
+#endif
+
+static const pa_channel_position_t gst_pos_to_pa[GST_AUDIO_CHANNEL_POSITION_NUM]
+ = {
+ [GST_AUDIO_CHANNEL_POSITION_FRONT_MONO] = PA_CHANNEL_POSITION_MONO,
+ [GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFT,
+ [GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHT,
+ [GST_AUDIO_CHANNEL_POSITION_REAR_CENTER] = PA_CHANNEL_POSITION_REAR_CENTER,
+ [GST_AUDIO_CHANNEL_POSITION_REAR_LEFT] = PA_CHANNEL_POSITION_REAR_LEFT,
+ [GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT] = PA_CHANNEL_POSITION_REAR_RIGHT,
+ [GST_AUDIO_CHANNEL_POSITION_LFE] = PA_CHANNEL_POSITION_LFE,
+ [GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTER,
+ [GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] =
+ PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
+ [GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] =
+ PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
+ [GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT] = PA_CHANNEL_POSITION_SIDE_LEFT,
+ [GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT] = PA_CHANNEL_POSITION_SIDE_RIGHT,
+ [GST_AUDIO_CHANNEL_POSITION_NONE] = PA_CHANNEL_POSITION_INVALID
+};
+
+/* All index are increased by one because PA_CHANNEL_POSITION_INVALID == -1 */
+static const GstAudioChannelPosition
+ pa_to_gst_pos[GST_AUDIO_CHANNEL_POSITION_NUM]
+ = {
+ [PA_CHANNEL_POSITION_MONO + 1] = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
+ [PA_CHANNEL_POSITION_FRONT_LEFT + 1] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ [PA_CHANNEL_POSITION_FRONT_RIGHT + 1] =
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ [PA_CHANNEL_POSITION_REAR_CENTER + 1] =
+ GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
+ [PA_CHANNEL_POSITION_REAR_LEFT + 1] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ [PA_CHANNEL_POSITION_REAR_RIGHT + 1] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ [PA_CHANNEL_POSITION_LFE + 1] = GST_AUDIO_CHANNEL_POSITION_LFE,
+ [PA_CHANNEL_POSITION_FRONT_CENTER + 1] =
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER + 1] =
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
+ [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER + 1] =
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
+ [PA_CHANNEL_POSITION_SIDE_LEFT + 1] = GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ [PA_CHANNEL_POSITION_SIDE_RIGHT + 1] = GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+ [PA_CHANNEL_POSITION_INVALID + 1] = GST_AUDIO_CHANNEL_POSITION_NONE,
+};
+
+gboolean
+gst_pulse_fill_sample_spec (GstRingBufferSpec * spec, pa_sample_spec * ss)
+{
+
+ if (spec->format == GST_MU_LAW && spec->width == 8)
+ ss->format = PA_SAMPLE_ULAW;
+ else if (spec->format == GST_A_LAW && spec->width == 8)
+ ss->format = PA_SAMPLE_ALAW;
+ else if (spec->format == GST_U8 && spec->width == 8)
+ ss->format = PA_SAMPLE_U8;
+ else if (spec->format == GST_S16_LE && spec->width == 16)
+ ss->format = PA_SAMPLE_S16LE;
+ else if (spec->format == GST_S16_BE && spec->width == 16)
+ ss->format = PA_SAMPLE_S16BE;
+ else if (spec->format == GST_FLOAT32_LE && spec->width == 32)
+ ss->format = PA_SAMPLE_FLOAT32LE;
+ else if (spec->format == GST_FLOAT32_BE && spec->width == 32)
+ ss->format = PA_SAMPLE_FLOAT32BE;
+ else if (spec->format == GST_S32_LE && spec->width == 32)
+ ss->format = PA_SAMPLE_S32LE;
+ else if (spec->format == GST_S32_BE && spec->width == 32)
+ ss->format = PA_SAMPLE_S32BE;
+ else if (spec->format == GST_S24_3LE && spec->width == 24)
+ ss->format = PA_SAMPLE_S24LE;
+ else if (spec->format == GST_S24_3BE && spec->width == 24)
+ ss->format = PA_SAMPLE_S24BE;
+ else if (spec->format == GST_S24_LE && spec->width == 32)
+ ss->format = PA_SAMPLE_S24_32LE;
+ else if (spec->format == GST_S24_BE && spec->width == 32)
+ ss->format = PA_SAMPLE_S24_32BE;
+ else
+ return FALSE;
+
+ ss->channels = spec->channels;
+ ss->rate = spec->rate;
+
+ if (!pa_sample_spec_valid (ss))
+ return FALSE;
+
+ return TRUE;
+}
+
+#ifdef HAVE_PULSE_1_0
+gboolean
+gst_pulse_fill_format_info (GstRingBufferSpec * spec, pa_format_info ** f,
+ guint * channels)
+{
+ pa_format_info *format;
+ pa_sample_format_t sf = PA_SAMPLE_INVALID;
+
+ format = pa_format_info_new ();
+
+ if (spec->format == GST_MU_LAW && spec->width == 8) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_ULAW;
+ } else if (spec->format == GST_A_LAW && spec->width == 8) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_ALAW;
+ } else if (spec->format == GST_U8 && spec->width == 8) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_U8;
+ } else if (spec->format == GST_S16_LE && spec->width == 16) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_S16LE;
+ } else if (spec->format == GST_S16_BE && spec->width == 16) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_S16BE;
+ } else if (spec->format == GST_FLOAT32_LE && spec->width == 32) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_FLOAT32LE;
+ } else if (spec->format == GST_FLOAT32_BE && spec->width == 32) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_FLOAT32BE;
+ } else if (spec->format == GST_S32_LE && spec->width == 32) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_S32LE;
+ } else if (spec->format == GST_S32_BE && spec->width == 32) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_S32BE;
+ } else if (spec->format == GST_S24_3LE && spec->width == 24) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_S24LE;
+ } else if (spec->format == GST_S24_3BE && spec->width == 24) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_S24BE;
+ } else if (spec->format == GST_S24_LE && spec->width == 32) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_S24_32LE;
+ } else if (spec->format == GST_S24_BE && spec->width == 32) {
+ format->encoding = PA_ENCODING_PCM;
+ sf = PA_SAMPLE_S24_32BE;
+ } else if (spec->format == GST_AC3) {
+ format->encoding = PA_ENCODING_AC3_IEC61937;
+ } else if (spec->format == GST_EAC3) {
+ format->encoding = PA_ENCODING_EAC3_IEC61937;
+ } else if (spec->format == GST_DTS) {
+ format->encoding = PA_ENCODING_DTS_IEC61937;
+ } else if (spec->format == GST_MPEG) {
+ format->encoding = PA_ENCODING_MPEG_IEC61937;
+ } else {
+ goto fail;
+ }
+
+ if (format->encoding == PA_ENCODING_PCM) {
+ pa_format_info_set_sample_format (format, sf);
+ pa_format_info_set_channels (format, spec->channels);
+ }
+
+ pa_format_info_set_rate (format, spec->rate);
+
+ if (!pa_format_info_valid (format))
+ goto fail;
+
+ *f = format;
+ *channels = spec->channels;
+
+ return TRUE;
+
+fail:
+ if (format)
+ pa_format_info_free (format);
+ return FALSE;
+}
+#endif
+
+/* PATH_MAX is not defined everywhere, e.g. on GNU Hurd */
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+gchar *
+gst_pulse_client_name (void)
+{
+ gchar buf[PATH_MAX];
+
+ const char *c;
+
+ if ((c = g_get_application_name ()))
+ return g_strdup (c);
+ else if (pa_get_binary_name (buf, sizeof (buf)))
+ return g_strdup (buf);
+ else
+ return g_strdup_printf ("GStreamer-pid-%lu", (gulong) getpid ());
+}
+
+pa_channel_map *
+gst_pulse_gst_to_channel_map (pa_channel_map * map,
+ const GstRingBufferSpec * spec)
+{
+ int i;
+ GstAudioChannelPosition *pos;
+
+ pa_channel_map_init (map);
+
+ if (!(pos =
+ gst_audio_get_channel_positions (gst_caps_get_structure (spec->caps,
+ 0)))) {
+ return NULL;
+ }
+
+ for (i = 0; i < spec->channels; i++) {
+ if (pos[i] == GST_AUDIO_CHANNEL_POSITION_NONE) {
+ /* no valid mappings for these channels */
+ g_free (pos);
+ return NULL;
+ } else if (pos[i] < GST_AUDIO_CHANNEL_POSITION_NUM)
+ map->map[i] = gst_pos_to_pa[pos[i]];
+ else
+ map->map[i] = PA_CHANNEL_POSITION_INVALID;
+ }
+
+ g_free (pos);
+ map->channels = spec->channels;
+
+ if (!pa_channel_map_valid (map)) {
+ return NULL;
+ }
+
+ return map;
+}
+
+GstRingBufferSpec *
+gst_pulse_channel_map_to_gst (const pa_channel_map * map,
+ GstRingBufferSpec * spec)
+{
+ int i;
+ GstAudioChannelPosition *pos;
+ gboolean invalid = FALSE;
+
+ g_return_val_if_fail (map->channels == spec->channels, NULL);
+
+ pos = g_new0 (GstAudioChannelPosition, spec->channels + 1);
+
+ for (i = 0; i < spec->channels; i++) {
+ if (map->map[i] == PA_CHANNEL_POSITION_INVALID) {
+ invalid = TRUE;
+ break;
+ } else if ((int) map->map[i] < (int) GST_AUDIO_CHANNEL_POSITION_NUM) {
+ pos[i] = pa_to_gst_pos[map->map[i] + 1];
+ } else {
+ invalid = TRUE;
+ break;
+ }
+ }
+
+ if (!invalid && !gst_audio_check_channel_positions (pos, spec->channels))
+ invalid = TRUE;
+
+ if (invalid) {
+ for (i = 0; i < spec->channels; i++)
+ pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
+ }
+
+ gst_audio_set_channel_positions (gst_caps_get_structure (spec->caps, 0), pos);
+
+ g_free (pos);
+
+ return spec;
+}
+
+void
+gst_pulse_cvolume_from_linear (pa_cvolume * v, unsigned channels,
+ gdouble volume)
+{
+ pa_cvolume_set (v, channels, pa_sw_volume_from_linear (volume));
+}
+
+static gboolean
+make_proplist_item (GQuark field_id, const GValue * value, gpointer user_data)
+{
+ pa_proplist *p = (pa_proplist *) user_data;
+ gchar *prop_id = (gchar *) g_quark_to_string (field_id);
+
+ /* http://0pointer.de/lennart/projects/pulseaudio/doxygen/proplist_8h.html */
+
+ /* match prop id */
+
+ /* check type */
+ switch (G_VALUE_TYPE (value)) {
+ case G_TYPE_STRING:
+ pa_proplist_sets (p, prop_id, g_value_get_string (value));
+ break;
+ default:
+ GST_WARNING ("unmapped property type %s", G_VALUE_TYPE_NAME (value));
+ break;
+ }
+
+ return TRUE;
+}
+
+pa_proplist *
+gst_pulse_make_proplist (const GstStructure * properties)
+{
+ pa_proplist *proplist = pa_proplist_new ();
+
+ /* iterate the structure and fill the proplist */
+ gst_structure_foreach (properties, make_proplist_item, proplist);
+ return proplist;
+}
diff --git a/ext/pulse/pulseutil.h b/ext/pulse/pulseutil.h
new file mode 100644
index 0000000..4adfeb1
--- /dev/null
+++ b/ext/pulse/pulseutil.h
@@ -0,0 +1,52 @@
+/*
+ * GStreamer pulseaudio plugin
+ *
+ * Copyright (c) 2004-2008 Lennart Poettering
+ *
+ * gst-pulse is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * gst-pulse is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with gst-pulse; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+#ifndef __GST_PULSEUTIL_H__
+#define __GST_PULSEUTIL_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <pulse/pulseaudio.h>
+#include <gst/audio/gstaudiosink.h>
+
+gboolean gst_pulse_fill_sample_spec (GstRingBufferSpec * spec,
+ pa_sample_spec * ss);
+#ifdef HAVE_PULSE_1_0
+gboolean gst_pulse_fill_format_info (GstRingBufferSpec * spec,
+ pa_format_info ** f, guint * channels);
+#endif
+
+gchar *gst_pulse_client_name (void);
+
+pa_channel_map *gst_pulse_gst_to_channel_map (pa_channel_map * map,
+ const GstRingBufferSpec * spec);
+
+GstRingBufferSpec *gst_pulse_channel_map_to_gst (const pa_channel_map * map,
+ GstRingBufferSpec * spec);
+
+void gst_pulse_cvolume_from_linear (pa_cvolume *v, unsigned channels, gdouble volume);
+
+pa_proplist *gst_pulse_make_proplist (const GstStructure *properties);
+
+#endif
diff --git a/ext/raw1394/Makefile.am b/ext/raw1394/Makefile.am
new file mode 100644
index 0000000..ae55f86
--- /dev/null
+++ b/ext/raw1394/Makefile.am
@@ -0,0 +1,29 @@
+plugin_LTLIBRARIES = libgst1394.la
+
+if USE_LIBIEC61883
+hdvsource = gsthdv1394src.c
+hdvheaders = gsthdv1394src.h
+else
+hdvsource =
+hdvheaders =
+endif
+
+libgst1394_la_SOURCES = \
+ gst1394.c gst1394probe.c gstdv1394src.c $(hdvsource) \
+ gst1394clock.c
+libgst1394_la_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) \
+ $(DV1394_CFLAGS)
+libgst1394_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS) \
+ $(DV1394_LIBS)
+libgst1394_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgst1394_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstdv1394src.h gst1394probe.h $(hdvheaders) \
+ gst1394clock.h
+
diff --git a/ext/raw1394/Makefile.in b/ext/raw1394/Makefile.in
new file mode 100644
index 0000000..0b4e7ac
--- /dev/null
+++ b/ext/raw1394/Makefile.in
@@ -0,0 +1,864 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/raw1394
+DIST_COMMON = $(am__noinst_HEADERS_DIST) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgst1394_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am__libgst1394_la_SOURCES_DIST = gst1394.c gst1394probe.c \
+ gstdv1394src.c gsthdv1394src.c gst1394clock.c
+@USE_LIBIEC61883_TRUE@am__objects_1 = libgst1394_la-gsthdv1394src.lo
+am_libgst1394_la_OBJECTS = libgst1394_la-gst1394.lo \
+ libgst1394_la-gst1394probe.lo libgst1394_la-gstdv1394src.lo \
+ $(am__objects_1) libgst1394_la-gst1394clock.lo
+libgst1394_la_OBJECTS = $(am_libgst1394_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgst1394_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgst1394_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgst1394_la_CFLAGS) $(CFLAGS) \
+ $(libgst1394_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgst1394_la_SOURCES)
+DIST_SOURCES = $(am__libgst1394_la_SOURCES_DIST)
+am__noinst_HEADERS_DIST = gstdv1394src.h gst1394probe.h \
+ gsthdv1394src.h gst1394clock.h
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgst1394.la
+@USE_LIBIEC61883_FALSE@hdvsource =
+@USE_LIBIEC61883_TRUE@hdvsource = gsthdv1394src.c
+@USE_LIBIEC61883_FALSE@hdvheaders =
+@USE_LIBIEC61883_TRUE@hdvheaders = gsthdv1394src.h
+libgst1394_la_SOURCES = \
+ gst1394.c gst1394probe.c gstdv1394src.c $(hdvsource) \
+ gst1394clock.c
+
+libgst1394_la_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) \
+ $(DV1394_CFLAGS)
+
+libgst1394_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS) \
+ $(DV1394_LIBS)
+
+libgst1394_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgst1394_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = gstdv1394src.h gst1394probe.h $(hdvheaders) \
+ gst1394clock.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/raw1394/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/raw1394/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgst1394.la: $(libgst1394_la_OBJECTS) $(libgst1394_la_DEPENDENCIES) $(EXTRA_libgst1394_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgst1394_la_LINK) -rpath $(plugindir) $(libgst1394_la_OBJECTS) $(libgst1394_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgst1394_la-gst1394.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgst1394_la-gst1394clock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgst1394_la-gst1394probe.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgst1394_la-gstdv1394src.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgst1394_la-gsthdv1394src.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgst1394_la-gst1394.lo: gst1394.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgst1394_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgst1394_la_CFLAGS) $(CFLAGS) -MT libgst1394_la-gst1394.lo -MD -MP -MF $(DEPDIR)/libgst1394_la-gst1394.Tpo -c -o libgst1394_la-gst1394.lo `test -f 'gst1394.c' || echo '$(srcdir)/'`gst1394.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgst1394_la-gst1394.Tpo $(DEPDIR)/libgst1394_la-gst1394.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gst1394.c' object='libgst1394_la-gst1394.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgst1394_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgst1394_la_CFLAGS) $(CFLAGS) -c -o libgst1394_la-gst1394.lo `test -f 'gst1394.c' || echo '$(srcdir)/'`gst1394.c
+
+libgst1394_la-gst1394probe.lo: gst1394probe.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgst1394_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgst1394_la_CFLAGS) $(CFLAGS) -MT libgst1394_la-gst1394probe.lo -MD -MP -MF $(DEPDIR)/libgst1394_la-gst1394probe.Tpo -c -o libgst1394_la-gst1394probe.lo `test -f 'gst1394probe.c' || echo '$(srcdir)/'`gst1394probe.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgst1394_la-gst1394probe.Tpo $(DEPDIR)/libgst1394_la-gst1394probe.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gst1394probe.c' object='libgst1394_la-gst1394probe.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgst1394_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgst1394_la_CFLAGS) $(CFLAGS) -c -o libgst1394_la-gst1394probe.lo `test -f 'gst1394probe.c' || echo '$(srcdir)/'`gst1394probe.c
+
+libgst1394_la-gstdv1394src.lo: gstdv1394src.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgst1394_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgst1394_la_CFLAGS) $(CFLAGS) -MT libgst1394_la-gstdv1394src.lo -MD -MP -MF $(DEPDIR)/libgst1394_la-gstdv1394src.Tpo -c -o libgst1394_la-gstdv1394src.lo `test -f 'gstdv1394src.c' || echo '$(srcdir)/'`gstdv1394src.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgst1394_la-gstdv1394src.Tpo $(DEPDIR)/libgst1394_la-gstdv1394src.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstdv1394src.c' object='libgst1394_la-gstdv1394src.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgst1394_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgst1394_la_CFLAGS) $(CFLAGS) -c -o libgst1394_la-gstdv1394src.lo `test -f 'gstdv1394src.c' || echo '$(srcdir)/'`gstdv1394src.c
+
+libgst1394_la-gsthdv1394src.lo: gsthdv1394src.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgst1394_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgst1394_la_CFLAGS) $(CFLAGS) -MT libgst1394_la-gsthdv1394src.lo -MD -MP -MF $(DEPDIR)/libgst1394_la-gsthdv1394src.Tpo -c -o libgst1394_la-gsthdv1394src.lo `test -f 'gsthdv1394src.c' || echo '$(srcdir)/'`gsthdv1394src.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgst1394_la-gsthdv1394src.Tpo $(DEPDIR)/libgst1394_la-gsthdv1394src.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gsthdv1394src.c' object='libgst1394_la-gsthdv1394src.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgst1394_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgst1394_la_CFLAGS) $(CFLAGS) -c -o libgst1394_la-gsthdv1394src.lo `test -f 'gsthdv1394src.c' || echo '$(srcdir)/'`gsthdv1394src.c
+
+libgst1394_la-gst1394clock.lo: gst1394clock.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgst1394_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgst1394_la_CFLAGS) $(CFLAGS) -MT libgst1394_la-gst1394clock.lo -MD -MP -MF $(DEPDIR)/libgst1394_la-gst1394clock.Tpo -c -o libgst1394_la-gst1394clock.lo `test -f 'gst1394clock.c' || echo '$(srcdir)/'`gst1394clock.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgst1394_la-gst1394clock.Tpo $(DEPDIR)/libgst1394_la-gst1394clock.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gst1394clock.c' object='libgst1394_la-gst1394clock.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgst1394_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgst1394_la_CFLAGS) $(CFLAGS) -c -o libgst1394_la-gst1394clock.lo `test -f 'gst1394clock.c' || echo '$(srcdir)/'`gst1394clock.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/raw1394/gst1394.c b/ext/raw1394/gst1394.c
new file mode 100644
index 0000000..dafeb73
--- /dev/null
+++ b/ext/raw1394/gst1394.c
@@ -0,0 +1,51 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <gst/gst.h>
+
+
+#include "gstdv1394src.h"
+#ifdef HAVE_LIBIEC61883
+#include "gsthdv1394src.h"
+#endif
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "dv1394src", GST_RANK_NONE,
+ GST_TYPE_DV1394SRC))
+ return FALSE;
+#ifdef HAVE_LIBIEC61883
+ if (!gst_element_register (plugin, "hdv1394src", GST_RANK_NONE,
+ GST_TYPE_HDV1394SRC))
+ return FALSE;
+#endif
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "1394",
+ "Source for video data via IEEE1394 interface",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/ext/raw1394/gst1394clock.c b/ext/raw1394/gst1394clock.c
new file mode 100644
index 0000000..0505c8c
--- /dev/null
+++ b/ext/raw1394/gst1394clock.c
@@ -0,0 +1,154 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ * Copyright (C) 2009 David Schleef <ds@schleef.org>
+ *
+ * gst1394clock.c: Clock for use by IEEE 1394 plugins
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gst1394clock.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_1394_clock_debug);
+#define GST_CAT_DEFAULT gst_1394_clock_debug
+
+static void gst_1394_clock_class_init (Gst1394ClockClass * klass);
+static void gst_1394_clock_init (Gst1394Clock * clock);
+
+static GstClockTime gst_1394_clock_get_internal_time (GstClock * clock);
+
+static GstSystemClockClass *parent_class = NULL;
+
+/* static guint gst_1394_clock_signals[LAST_SIGNAL] = { 0 }; */
+
+GType
+gst_1394_clock_get_type (void)
+{
+ static GType clock_type = 0;
+
+ if (!clock_type) {
+ static const GTypeInfo clock_info = {
+ sizeof (Gst1394ClockClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gst_1394_clock_class_init,
+ NULL,
+ NULL,
+ sizeof (Gst1394Clock),
+ 4,
+ (GInstanceInitFunc) gst_1394_clock_init,
+ NULL
+ };
+
+ clock_type = g_type_register_static (GST_TYPE_SYSTEM_CLOCK, "Gst1394Clock",
+ &clock_info, 0);
+ }
+ return clock_type;
+}
+
+
+static void
+gst_1394_clock_class_init (Gst1394ClockClass * klass)
+{
+ GstClockClass *gstclock_class;
+
+ gstclock_class = (GstClockClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gstclock_class->get_internal_time = gst_1394_clock_get_internal_time;
+
+ GST_DEBUG_CATEGORY_INIT (gst_1394_clock_debug, "1394clock", 0, "1394clock");
+}
+
+static void
+gst_1394_clock_init (Gst1394Clock * clock)
+{
+ GST_OBJECT_FLAG_SET (clock, GST_CLOCK_FLAG_CAN_SET_MASTER);
+}
+
+/**
+ * gst_1394_clock_new:
+ * @name: the name of the clock
+ *
+ * Create a new #Gst1394Clock instance.
+ *
+ * Returns: a new #Gst1394Clock
+ */
+Gst1394Clock *
+gst_1394_clock_new (const gchar * name)
+{
+ Gst1394Clock *_1394clock =
+ GST_1394_CLOCK (g_object_new (GST_TYPE_1394_CLOCK, "name", name, NULL));
+
+ return _1394clock;
+}
+
+static GstClockTime
+gst_1394_clock_get_internal_time (GstClock * clock)
+{
+ Gst1394Clock *_1394clock;
+ GstClockTime result;
+ guint32 cycle_timer;
+ guint64 local_time;
+
+ _1394clock = GST_1394_CLOCK_CAST (clock);
+
+ if (_1394clock->handle != NULL) {
+ GST_OBJECT_LOCK (clock);
+ raw1394_read_cycle_timer (_1394clock->handle, &cycle_timer, &local_time);
+
+ if (cycle_timer < _1394clock->cycle_timer_lo) {
+ GST_LOG_OBJECT (clock, "overflow %u to %u",
+ _1394clock->cycle_timer_lo, cycle_timer);
+
+ _1394clock->cycle_timer_hi++;
+ }
+ _1394clock->cycle_timer_lo = cycle_timer;
+
+ /* get the seconds from the cycleSeconds counter */
+ result = (((((guint64) _1394clock->cycle_timer_hi) << 32) |
+ cycle_timer) >> 25) * GST_SECOND;
+ /* add the microseconds from the cycleCount counter */
+ result += (((cycle_timer >> 12) & 0x1fff) * 125) * GST_USECOND;
+
+ GST_LOG_OBJECT (clock, "result %" GST_TIME_FORMAT, GST_TIME_ARGS (result));
+ GST_OBJECT_UNLOCK (clock);
+ } else {
+ result = GST_CLOCK_TIME_NONE;
+ }
+
+ return result;
+}
+
+void
+gst_1394_clock_set_handle (Gst1394Clock * clock, raw1394handle_t handle)
+{
+ clock->handle = handle;
+ clock->cycle_timer_lo = 0;
+ clock->cycle_timer_hi = 0;
+}
+
+void
+gst_1394_clock_unset_handle (Gst1394Clock * clock)
+{
+ clock->handle = NULL;
+}
diff --git a/ext/raw1394/gst1394clock.h b/ext/raw1394/gst1394clock.h
new file mode 100644
index 0000000..ab7594d
--- /dev/null
+++ b/ext/raw1394/gst1394clock.h
@@ -0,0 +1,77 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2005 Wim Taymans <wim@fluendo.com>
+ * Copyright (C) 2009 David Schleef <ds@schleef.org>
+ *
+ * gst1394clock.h: Clock for use by the IEEE 1394
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_1394_CLOCK_H__
+#define __GST_1394_CLOCK_H__
+
+#include <gst/gst.h>
+#include <gst/gstsystemclock.h>
+
+#include <libraw1394/raw1394.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_1394_CLOCK \
+ (gst_1394_clock_get_type())
+#define GST_1394_CLOCK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_1394_CLOCK,Gst1394Clock))
+#define GST_1394_CLOCK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_1394_CLOCK,Gst1394ClockClass))
+#define GST_IS_1394_CLOCK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_1394_CLOCK))
+#define GST_IS_1394_CLOCK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_1394_CLOCK))
+#define GST_1394_CLOCK_CAST(obj) \
+ ((Gst1394Clock*)(obj))
+
+typedef struct _Gst1394Clock Gst1394Clock;
+typedef struct _Gst1394ClockClass Gst1394ClockClass;
+
+/**
+ * Gst1394Clock:
+ * @clock: parent #GstSystemClock
+ *
+ * Opaque #Gst1394Clock.
+ */
+struct _Gst1394Clock {
+ GstSystemClock clock;
+
+ raw1394handle_t handle;
+
+ guint32 cycle_timer_lo;
+ guint32 cycle_timer_hi;
+};
+
+struct _Gst1394ClockClass {
+ GstSystemClockClass parent_class;
+};
+
+GType gst_1394_clock_get_type (void);
+Gst1394Clock* gst_1394_clock_new (const gchar *name);
+void gst_1394_clock_set_handle (Gst1394Clock *clock,
+ raw1394handle_t handle);
+void gst_1394_clock_unset_handle (Gst1394Clock *clock);
+
+G_END_DECLS
+
+#endif /* __GST_1394_CLOCK_H__ */
diff --git a/ext/raw1394/gst1394probe.c b/ext/raw1394/gst1394probe.c
new file mode 100644
index 0000000..ee51ba0
--- /dev/null
+++ b/ext/raw1394/gst1394probe.c
@@ -0,0 +1,140 @@
+/* GStreamer
+ * Copyright (C) 2007 Julien Puydt <jpuydt@free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libavc1394/avc1394.h>
+#include <libavc1394/avc1394_vcr.h>
+#include <libavc1394/rom1394.h>
+#include <libraw1394/raw1394.h>
+
+#include <gst/gst.h>
+
+#include "gst1394probe.h"
+#include "gst/interfaces/propertyprobe.h"
+
+static GValueArray *
+gst_1394_get_guid_array (void)
+{
+ GValueArray *result = NULL;
+ raw1394handle_t handle = NULL;
+ int num_ports = 0;
+ int port = 0;
+ int num_nodes = 0;
+ int node = 0;
+ rom1394_directory directory;
+ GValue value = { 0, };
+
+ handle = raw1394_new_handle ();
+
+ if (handle == NULL)
+ return NULL;
+
+ num_ports = raw1394_get_port_info (handle, NULL, 0);
+ for (port = 0; port < num_ports; port++) {
+ if (raw1394_set_port (handle, port) >= 0) {
+ num_nodes = raw1394_get_nodecount (handle);
+ for (node = 0; node < num_nodes; node++) {
+ rom1394_get_directory (handle, node, &directory);
+ if (rom1394_get_node_type (&directory) == ROM1394_NODE_TYPE_AVC &&
+ avc1394_check_subunit_type (handle, node,
+ AVC1394_SUBUNIT_TYPE_VCR)) {
+ if (result == NULL)
+ result = g_value_array_new (3); /* looks like a sensible default */
+ g_value_init (&value, G_TYPE_UINT64);
+ g_value_set_uint64 (&value, rom1394_get_guid (handle, node));
+ g_value_array_append (result, &value);
+ g_value_unset (&value);
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static const GList *
+gst_1394_property_probe_get_properties (GstPropertyProbe * probe)
+{
+ static GList *result = NULL;
+ GObjectClass *klass = NULL;
+ GParamSpec *spec = NULL;
+
+ if (result == NULL) {
+ klass = G_OBJECT_GET_CLASS (probe);
+ spec = g_object_class_find_property (klass, "guid");
+ result = g_list_append (result, spec);
+ }
+
+ return result;
+}
+
+static void
+gst_1394_property_probe_probe_property (GstPropertyProbe * probe, guint prop_id,
+ const GParamSpec * pspec)
+{
+ if (!g_str_equal (pspec->name, "guid"))
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
+}
+
+static gboolean
+gst_1394_property_probe_needs_probe (GstPropertyProbe * probe, guint prop_id,
+ const GParamSpec * pspec)
+{
+ return TRUE;
+}
+
+static GValueArray *
+gst_1394_property_probe_get_values (GstPropertyProbe * probe, guint prop_id,
+ const GParamSpec * pspec)
+{
+ GValueArray *result = NULL;
+
+ if (!g_str_equal (pspec->name, "guid")) {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
+ return NULL;
+ }
+
+ result = gst_1394_get_guid_array ();
+
+ if (result == NULL)
+ GST_LOG_OBJECT (probe, "No guid found");
+
+ return result;
+}
+
+static void
+gst_1394_property_probe_interface_init (GstPropertyProbeInterface * iface)
+{
+ iface->get_properties = gst_1394_property_probe_get_properties;
+ iface->probe_property = gst_1394_property_probe_probe_property;
+ iface->needs_probe = gst_1394_property_probe_needs_probe;
+ iface->get_values = gst_1394_property_probe_get_values;
+}
+
+void
+gst_1394_type_add_property_probe_interface (GType type)
+{
+ static const GInterfaceInfo probe_iface_info = {
+ (GInterfaceInitFunc) gst_1394_property_probe_interface_init,
+ NULL,
+ NULL,
+ };
+
+ g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
+ &probe_iface_info);
+}
diff --git a/ext/raw1394/gst1394probe.h b/ext/raw1394/gst1394probe.h
new file mode 100644
index 0000000..8436e70
--- /dev/null
+++ b/ext/raw1394/gst1394probe.h
@@ -0,0 +1,32 @@
+/* GStreamer
+ * Copyright (C) 2007 Julien Puydt <jpuydt@free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GST_1394_PROBE_H
+#define GST_1394_PROBE_H
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+void gst_1394_type_add_property_probe_interface (GType type);
+
+G_END_DECLS
+
+#endif /* __GST_1394_PROBE_H */
+
diff --git a/ext/raw1394/gstdv1394src.c b/ext/raw1394/gstdv1394src.c
new file mode 100644
index 0000000..1a3cae6
--- /dev/null
+++ b/ext/raw1394/gstdv1394src.c
@@ -0,0 +1,1134 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * <2000> Daniel Fischer <dan@f3c.com>
+ * <2004> Wim Taymans <wim@fluendo.com>
+ * <2006> Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:element-dv1394src
+ *
+ * Read DV (digital video) data from firewire port.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch dv1394src ! queue ! dvdemux name=d ! queue ! dvdec ! xvimagesink d. ! queue ! alsasink
+ * ]| This pipeline captures from the firewire port and displays it (might need
+ * format converters for audio/video).
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <libavc1394/avc1394.h>
+#include <libavc1394/avc1394_vcr.h>
+#include <libavc1394/rom1394.h>
+#include <libraw1394/raw1394.h>
+#ifdef HAVE_LIBIEC61883
+#include <libiec61883/iec61883.h>
+#endif
+
+#include <gst/gst.h>
+
+#include "gstdv1394src.h"
+#include "gst1394probe.h"
+#include "gst1394clock.h"
+
+
+#define CONTROL_STOP 'S' /* stop the select call */
+#define CONTROL_SOCKETS(src) src->control_sock
+#define WRITE_SOCKET(src) src->control_sock[1]
+#define READ_SOCKET(src) src->control_sock[0]
+
+#define SEND_COMMAND(src, command) \
+G_STMT_START { \
+ int G_GNUC_UNUSED _res; unsigned char c; c = command; \
+ _res = write (WRITE_SOCKET(src), &c, 1); \
+} G_STMT_END
+
+#define READ_COMMAND(src, command, res) \
+G_STMT_START { \
+ res = read(READ_SOCKET(src), &command, 1); \
+} G_STMT_END
+
+
+GST_DEBUG_CATEGORY_STATIC (dv1394src_debug);
+#define GST_CAT_DEFAULT (dv1394src_debug)
+
+#define PAL_FRAMESIZE 144000
+#define PAL_FRAMERATE 25
+
+#define NTSC_FRAMESIZE 120000
+#define NTSC_FRAMERATE 30
+
+enum
+{
+ SIGNAL_FRAME_DROPPED,
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+#define DEFAULT_PORT -1
+#define DEFAULT_CHANNEL 63
+#define DEFAULT_CONSECUTIVE 1
+#define DEFAULT_SKIP 0
+#define DEFAULT_DROP_INCOMPLETE TRUE
+#define DEFAULT_USE_AVC TRUE
+#define DEFAULT_GUID 0
+
+enum
+{
+ PROP_0,
+ PROP_PORT,
+ PROP_CHANNEL,
+ PROP_CONSECUTIVE,
+ PROP_SKIP,
+ PROP_DROP_INCOMPLETE,
+ PROP_USE_AVC,
+ PROP_GUID,
+ PROP_DEVICE_NAME
+};
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-dv, "
+ "format = (string) { NTSC, PAL }, " "systemstream = (boolean) true")
+ );
+
+static void gst_dv1394src_uri_handler_init (gpointer g_iface,
+ gpointer iface_data);
+
+static void gst_dv1394src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_dv1394src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_dv1394src_dispose (GObject * object);
+
+static GstClock *gst_dv1394src_provide_clock (GstElement * element);
+static GstStateChangeReturn gst_dv1394_src_change_state (GstElement * element,
+ GstStateChange transition);
+
+static gboolean gst_dv1394src_start (GstBaseSrc * bsrc);
+static gboolean gst_dv1394src_stop (GstBaseSrc * bsrc);
+static gboolean gst_dv1394src_unlock (GstBaseSrc * bsrc);
+
+static GstFlowReturn gst_dv1394src_create (GstPushSrc * psrc, GstBuffer ** buf);
+
+static gboolean gst_dv1394src_query (GstBaseSrc * src, GstQuery * query);
+static void gst_dv1394src_update_device_name (GstDV1394Src * src);
+
+static void
+_do_init (GType type)
+{
+ static const GInterfaceInfo urihandler_info = {
+ gst_dv1394src_uri_handler_init,
+ NULL,
+ NULL,
+ };
+ g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
+
+ gst_1394_type_add_property_probe_interface (type);
+
+ GST_DEBUG_CATEGORY_INIT (dv1394src_debug, "dv1394src", 0,
+ "DV firewire source");
+}
+
+GST_BOILERPLATE_FULL (GstDV1394Src, gst_dv1394src, GstPushSrc,
+ GST_TYPE_PUSH_SRC, _do_init);
+
+
+static guint gst_dv1394src_signals[LAST_SIGNAL] = { 0 };
+
+
+static void
+gst_dv1394src_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class, &src_factory);
+
+ gst_element_class_set_details_simple (element_class,
+ "Firewire (1394) DV video source", "Source/Video",
+ "Source for DV video data from firewire port",
+ "Erik Walthinsen <omega@temple-baptist.com>, "
+ "Daniel Fischer <dan@f3c.com>, " "Wim Taymans <wim@fluendo.com>, "
+ "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
+}
+
+static void
+gst_dv1394src_class_init (GstDV1394SrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstBaseSrcClass *gstbasesrc_class;
+ GstPushSrcClass *gstpushsrc_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstbasesrc_class = (GstBaseSrcClass *) klass;
+ gstpushsrc_class = (GstPushSrcClass *) klass;
+
+ gobject_class->set_property = gst_dv1394src_set_property;
+ gobject_class->get_property = gst_dv1394src_get_property;
+ gobject_class->dispose = gst_dv1394src_dispose;
+
+ gstelement_class->provide_clock = gst_dv1394src_provide_clock;
+ gstelement_class->change_state = gst_dv1394_src_change_state;
+
+ gst_dv1394src_signals[SIGNAL_FRAME_DROPPED] =
+ g_signal_new ("frame-dropped", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDV1394SrcClass, frame_dropped),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
+ g_param_spec_int ("port", "Port", "Port number (-1 automatic)",
+ -1, 16, DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CHANNEL,
+ g_param_spec_int ("channel", "Channel", "Channel number for listening",
+ 0, 64, DEFAULT_CHANNEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CONSECUTIVE,
+ g_param_spec_int ("consecutive", "consecutive frames",
+ "send n consecutive frames after skipping", 1, G_MAXINT,
+ DEFAULT_CONSECUTIVE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SKIP,
+ g_param_spec_int ("skip", "skip frames", "skip n frames",
+ 0, G_MAXINT, DEFAULT_SKIP,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DROP_INCOMPLETE,
+ g_param_spec_boolean ("drop-incomplete", "drop incomplete",
+ "drop incomplete frames", DEFAULT_DROP_INCOMPLETE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_USE_AVC,
+ g_param_spec_boolean ("use-avc", "Use AV/C", "Use AV/C VTR control",
+ DEFAULT_USE_AVC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GUID,
+ g_param_spec_uint64 ("guid", "GUID",
+ "select one of multiple DV devices by its GUID. use a hexadecimal "
+ "like 0xhhhhhhhhhhhhhhhh. (0 = no guid)", 0, G_MAXUINT64,
+ DEFAULT_GUID, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstDV1394Src:device-name
+ *
+ * Descriptive name of the currently opened device
+ *
+ * Since: 0.10.7
+ **/
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEVICE_NAME,
+ g_param_spec_string ("device-name", "device name",
+ "user-friendly name of the device", "Default",
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ gstbasesrc_class->negotiate = NULL;
+ gstbasesrc_class->start = gst_dv1394src_start;
+ gstbasesrc_class->stop = gst_dv1394src_stop;
+ gstbasesrc_class->unlock = gst_dv1394src_unlock;
+ gstbasesrc_class->query = gst_dv1394src_query;
+
+ gstpushsrc_class->create = gst_dv1394src_create;
+}
+
+static void
+gst_dv1394src_init (GstDV1394Src * dv1394src, GstDV1394SrcClass * klass)
+{
+ GstPad *srcpad = GST_BASE_SRC_PAD (dv1394src);
+
+ gst_base_src_set_live (GST_BASE_SRC (dv1394src), TRUE);
+ gst_base_src_set_format (GST_BASE_SRC (dv1394src), GST_FORMAT_TIME);
+ gst_base_src_set_do_timestamp (GST_BASE_SRC (dv1394src), TRUE);
+ gst_pad_use_fixed_caps (srcpad);
+
+ dv1394src->port = DEFAULT_PORT;
+ dv1394src->channel = DEFAULT_CHANNEL;
+
+ dv1394src->consecutive = DEFAULT_CONSECUTIVE;
+ dv1394src->skip = DEFAULT_SKIP;
+ dv1394src->drop_incomplete = DEFAULT_DROP_INCOMPLETE;
+ dv1394src->use_avc = DEFAULT_USE_AVC;
+ dv1394src->guid = DEFAULT_GUID;
+ dv1394src->uri = g_strdup_printf ("dv://%d", dv1394src->port);
+ dv1394src->device_name = g_strdup_printf ("Default");
+
+ READ_SOCKET (dv1394src) = -1;
+ WRITE_SOCKET (dv1394src) = -1;
+
+ /* initialized when first header received */
+ dv1394src->frame_size = 0;
+
+ dv1394src->buf = NULL;
+ dv1394src->frame = NULL;
+ dv1394src->frame_sequence = 0;
+
+ dv1394src->provided_clock = gst_1394_clock_new ("dv1394clock");
+}
+
+static void
+gst_dv1394src_dispose (GObject * object)
+{
+ GstDV1394Src *src = GST_DV1394SRC (object);
+
+ if (src->provided_clock) {
+ g_object_unref (src->provided_clock);
+ }
+
+ g_free (src->uri);
+ src->uri = NULL;
+
+ g_free (src->device_name);
+ src->device_name = NULL;
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_dv1394src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstDV1394Src *filter = GST_DV1394SRC (object);
+
+ switch (prop_id) {
+ case PROP_PORT:
+ filter->port = g_value_get_int (value);
+ g_free (filter->uri);
+ filter->uri = g_strdup_printf ("dv://%d", filter->port);
+ break;
+ case PROP_CHANNEL:
+ filter->channel = g_value_get_int (value);
+ break;
+ case PROP_SKIP:
+ filter->skip = g_value_get_int (value);
+ break;
+ case PROP_CONSECUTIVE:
+ filter->consecutive = g_value_get_int (value);
+ break;
+ case PROP_DROP_INCOMPLETE:
+ filter->drop_incomplete = g_value_get_boolean (value);
+ break;
+ case PROP_USE_AVC:
+ filter->use_avc = g_value_get_boolean (value);
+ break;
+ case PROP_GUID:
+ filter->guid = g_value_get_uint64 (value);
+ gst_dv1394src_update_device_name (filter);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_dv1394src_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstDV1394Src *filter = GST_DV1394SRC (object);
+
+ switch (prop_id) {
+ case PROP_PORT:
+ g_value_set_int (value, filter->port);
+ break;
+ case PROP_CHANNEL:
+ g_value_set_int (value, filter->channel);
+ break;
+ case PROP_SKIP:
+ g_value_set_int (value, filter->skip);
+ break;
+ case PROP_CONSECUTIVE:
+ g_value_set_int (value, filter->consecutive);
+ break;
+ case PROP_DROP_INCOMPLETE:
+ g_value_set_boolean (value, filter->drop_incomplete);
+ break;
+ case PROP_USE_AVC:
+ g_value_set_boolean (value, filter->use_avc);
+ break;
+ case PROP_GUID:
+ g_value_set_uint64 (value, filter->guid);
+ break;
+ case PROP_DEVICE_NAME:
+ g_value_set_string (value, filter->device_name);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstClock *
+gst_dv1394src_provide_clock (GstElement * element)
+{
+ GstDV1394Src *dv1394src = GST_DV1394SRC (element);
+
+ return GST_CLOCK_CAST (gst_object_ref (dv1394src->provided_clock));
+}
+
+static GstStateChangeReturn
+gst_dv1394_src_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstDV1394Src *src = GST_DV1394SRC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ gst_element_post_message (element,
+ gst_message_new_clock_lost (GST_OBJECT_CAST (element),
+ GST_CLOCK_CAST (src->provided_clock)));
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ gst_element_post_message (element,
+ gst_message_new_clock_provide (GST_OBJECT_CAST (element),
+ GST_CLOCK_CAST (src->provided_clock), TRUE));
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+#ifdef HAVE_LIBIEC61883
+static GstDV1394Src *
+gst_dv1394src_from_raw1394handle (raw1394handle_t handle)
+{
+ iec61883_dv_t dv = (iec61883_dv_t) raw1394_get_userdata (handle);
+ iec61883_dv_fb_t dv_fb =
+ (iec61883_dv_fb_t) iec61883_dv_get_callback_data (dv);
+ return GST_DV1394SRC (iec61883_dv_fb_get_callback_data (dv_fb));
+}
+#else /* HAVE_LIBIEC61883 */
+static GstDV1394Src *
+gst_dv1394src_from_raw1394handle (raw1394handle_t handle)
+{
+ return GST_DV1394SRC (raw1394_get_userdata (handle));
+}
+#endif /* HAVE_LIBIEC61883 */
+
+#ifdef HAVE_LIBIEC61883
+static int
+gst_dv1394src_iec61883_receive (unsigned char *data, int len,
+ int complete, void *cbdata)
+{
+ GstDV1394Src *dv1394src = GST_DV1394SRC (cbdata);
+
+ if (G_UNLIKELY (!GST_PAD_CAPS (GST_BASE_SRC_PAD (dv1394src)))) {
+ GstCaps *caps;
+ unsigned char *p = data;
+
+ // figure format (NTSC/PAL)
+ if (p[3] & 0x80) {
+ // PAL
+ dv1394src->frame_size = PAL_FRAMESIZE;
+ dv1394src->frame_rate = PAL_FRAMERATE;
+ GST_DEBUG ("PAL data");
+ caps = gst_caps_new_simple ("video/x-dv",
+ "format", G_TYPE_STRING, "PAL",
+ "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+ } else {
+ // NTSC (untested)
+ dv1394src->frame_size = NTSC_FRAMESIZE;
+ dv1394src->frame_rate = NTSC_FRAMERATE;
+ GST_DEBUG
+ ("NTSC data [untested] - please report success/failure to <dan@f3c.com>");
+ caps = gst_caps_new_simple ("video/x-dv",
+ "format", G_TYPE_STRING, "NTSC",
+ "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+ }
+ gst_pad_set_caps (GST_BASE_SRC_PAD (dv1394src), caps);
+ gst_caps_unref (caps);
+ }
+
+ dv1394src->frame = NULL;
+ if (G_LIKELY ((dv1394src->frame_sequence + 1) % (dv1394src->skip +
+ dv1394src->consecutive) < dv1394src->consecutive)) {
+ if (complete && len == dv1394src->frame_size) {
+ guint8 *bufdata;
+ GstBuffer *buf;
+
+ buf = gst_buffer_new_and_alloc (dv1394src->frame_size);
+
+ GST_BUFFER_OFFSET (buf) = dv1394src->frame_sequence;
+ bufdata = GST_BUFFER_DATA (buf);
+ memcpy (bufdata, data, len);
+ dv1394src->buf = buf;
+ }
+ }
+ dv1394src->frame_sequence++;
+ return 0;
+}
+
+#else
+static int
+gst_dv1394src_iso_receive (raw1394handle_t handle, int channel, size_t len,
+ quadlet_t * data)
+{
+ GstDV1394Src *dv1394src = gst_dv1394src_from_raw1394handle (handle);
+
+ if (len > 16) {
+ /*
+ the following code taken from kino-0.51 (Dan Dennedy/Charles Yates)
+ Kindly relicensed under the LGPL. See the commit log for version 1.6 of
+ this file in CVS.
+ */
+ unsigned char *p = (unsigned char *) &data[3];
+
+ int section_type = p[0] >> 5; /* section type is in bits 5 - 7 */
+ int dif_sequence = p[1] >> 4; /* dif sequence number is in bits 4 - 7 */
+ int dif_block = p[2];
+
+ /* if we are at the beginning of a frame,
+ we set buf=frame, and alloc a new buffer for frame
+ */
+ if (section_type == 0 && dif_sequence == 0) { // dif header
+ if (!GST_PAD_CAPS (GST_BASE_SRC_PAD (dv1394src))) {
+ GstCaps *caps;
+
+ // figure format (NTSC/PAL)
+ if (p[3] & 0x80) {
+ // PAL
+ dv1394src->frame_size = PAL_FRAMESIZE;
+ dv1394src->frame_rate = PAL_FRAMERATE;
+ GST_DEBUG ("PAL data");
+ caps = gst_caps_new_simple ("video/x-dv",
+ "format", G_TYPE_STRING, "PAL",
+ "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+ } else {
+ // NTSC (untested)
+ dv1394src->frame_size = NTSC_FRAMESIZE;
+ dv1394src->frame_rate = NTSC_FRAMERATE;
+ GST_DEBUG
+ ("NTSC data [untested] - please report success/failure to <dan@f3c.com>");
+ caps = gst_caps_new_simple ("video/x-dv",
+ "format", G_TYPE_STRING, "NTSC",
+ "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+ }
+ gst_pad_set_caps (GST_BASE_SRC_PAD (dv1394src), caps);
+ gst_caps_unref (caps);
+ }
+ // drop last frame when not complete
+ if (!dv1394src->drop_incomplete
+ || dv1394src->bytes_in_frame == dv1394src->frame_size) {
+ dv1394src->buf = dv1394src->frame;
+ } else {
+ GST_INFO_OBJECT (GST_ELEMENT (dv1394src), "incomplete frame dropped");
+ g_signal_emit (G_OBJECT (dv1394src),
+ gst_dv1394src_signals[SIGNAL_FRAME_DROPPED], 0);
+ if (dv1394src->frame) {
+ gst_buffer_unref (dv1394src->frame);
+ }
+ }
+ if ((dv1394src->frame_sequence + 1) % (dv1394src->skip +
+ dv1394src->consecutive) < dv1394src->consecutive) {
+ GstBuffer *buf;
+ gint64 i64;
+
+ buf = gst_buffer_new_and_alloc (dv1394src->frame_size);
+
+ /* fill in offset, duration, timestamp */
+ GST_BUFFER_OFFSET (buf) = dv1394src->frame_sequence;
+ dv1394src->frame = buf;
+ }
+ dv1394src->frame_sequence++;
+ dv1394src->bytes_in_frame = 0;
+ }
+
+ if (dv1394src->frame != NULL) {
+ guint8 *data = GST_BUFFER_DATA (dv1394src->frame);
+
+ switch (section_type) {
+ case 0: /* 1 Header block */
+ /* p[3] |= 0x80; // hack to force PAL data */
+ memcpy (data + dif_sequence * 150 * 80, p, 480);
+ break;
+
+ case 1: /* 2 Subcode blocks */
+ memcpy (data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p,
+ 480);
+ break;
+
+ case 2: /* 3 VAUX blocks */
+ memcpy (data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p,
+ 480);
+ break;
+
+ case 3: /* 9 Audio blocks interleaved with video */
+ memcpy (data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p,
+ 480);
+ break;
+
+ case 4: /* 135 Video blocks interleaved with audio */
+ memcpy (data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) +
+ dif_block) * 80, p, 480);
+ break;
+
+ default: /* we can't handle any other data */
+ break;
+ }
+ dv1394src->bytes_in_frame += 480;
+ }
+ }
+
+ return 0;
+}
+#endif
+/*
+ * When an ieee1394 bus reset happens, usually a device has been removed
+ * or added. We send a message on the message bus with the node count
+ * and whether the capture device used in this element connected, disconnected
+ * or was unchanged
+ * Message structure:
+ * nodecount - integer with number of nodes on bus
+ * current-device-change - integer (1 if device connected, 0 if no change to
+ * current device status, -1 if device disconnected)
+ */
+static int
+gst_dv1394src_bus_reset (raw1394handle_t handle, unsigned int generation)
+{
+ GstDV1394Src *src;
+ gint nodecount;
+ GstMessage *message;
+ GstStructure *structure;
+ gint current_device_change;
+ gint i;
+
+ src = gst_dv1394src_from_raw1394handle (handle);
+
+ GST_INFO_OBJECT (src, "have bus reset");
+
+ /* update generation - told to do so by docs */
+ raw1394_update_generation (handle, generation);
+ nodecount = raw1394_get_nodecount (handle);
+ /* allocate memory for portinfo */
+
+ /* current_device_change is -1 if camera disconnected, 0 if other device
+ * connected or 1 if camera has now connected */
+ current_device_change = -1;
+ for (i = 0; i < nodecount; i++) {
+ if (src->guid == rom1394_get_guid (handle, i)) {
+ /* Camera is with us */
+ GST_DEBUG ("Camera is with us");
+ if (!src->connected) {
+ current_device_change = 1;
+ src->connected = TRUE;
+ } else
+ current_device_change = 0;
+ }
+ }
+ if (src->connected && current_device_change == -1) {
+ GST_DEBUG ("Camera has disconnected");
+ src->connected = FALSE;
+ } else if (!src->connected && current_device_change == -1) {
+ GST_DEBUG ("Camera is still not with us");
+ current_device_change = 0;
+ }
+
+ structure = gst_structure_new ("ieee1394-bus-reset", "nodecount", G_TYPE_INT,
+ nodecount, "current-device-change", G_TYPE_INT, current_device_change,
+ NULL);
+ message = gst_message_new_element (GST_OBJECT (src), structure);
+ gst_element_post_message (GST_ELEMENT (src), message);
+
+ return 0;
+}
+
+static GstFlowReturn
+gst_dv1394src_create (GstPushSrc * psrc, GstBuffer ** buf)
+{
+ GstDV1394Src *dv1394src = GST_DV1394SRC (psrc);
+ GstCaps *caps;
+ struct pollfd pollfds[2];
+
+ pollfds[0].fd = raw1394_get_fd (dv1394src->handle);
+ pollfds[0].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
+ pollfds[1].fd = READ_SOCKET (dv1394src);
+ pollfds[1].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
+
+ if (G_UNLIKELY (dv1394src->buf)) {
+ /* maybe we had an error before, and there's a stale buffer? */
+ gst_buffer_unref (dv1394src->buf);
+ dv1394src->buf = NULL;
+ }
+
+ while (TRUE) {
+ int res = poll (pollfds, 2, -1);
+
+ if (G_UNLIKELY (res < 0)) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ else
+ goto error_while_polling;
+ }
+
+ if (G_UNLIKELY (pollfds[1].revents)) {
+ char command;
+
+ if (pollfds[1].revents & POLLIN)
+ READ_COMMAND (dv1394src, command, res);
+
+ goto told_to_stop;
+ } else if (G_LIKELY (pollfds[0].revents & POLLIN)) {
+ /* shouldn't block in theory */
+ raw1394_loop_iterate (dv1394src->handle);
+
+ if (dv1394src->buf)
+ break;
+ }
+ }
+
+ g_assert (dv1394src->buf);
+
+ caps = gst_pad_get_caps (GST_BASE_SRC_PAD (psrc));
+ gst_buffer_set_caps (dv1394src->buf, caps);
+ gst_caps_unref (caps);
+
+ *buf = dv1394src->buf;
+ dv1394src->buf = NULL;
+ return GST_FLOW_OK;
+
+error_while_polling:
+ {
+ GST_ELEMENT_ERROR (dv1394src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
+ return GST_FLOW_UNEXPECTED;
+ }
+told_to_stop:
+ {
+ GST_DEBUG_OBJECT (dv1394src, "told to stop, shutting down");
+ return GST_FLOW_WRONG_STATE;
+ }
+}
+
+static int
+gst_dv1394src_discover_avc_node (GstDV1394Src * src)
+{
+ int node = -1;
+ int i, j = 0;
+ int m = src->num_ports;
+
+ if (src->port >= 0) {
+ /* search on explicit port */
+ j = src->port;
+ m = j + 1;
+ }
+
+ /* loop over all our ports */
+ for (; j < m && node == -1; j++) {
+ raw1394handle_t handle;
+ struct raw1394_portinfo pinf[16];
+
+ /* open the port */
+ handle = raw1394_new_handle ();
+ if (!handle) {
+ GST_WARNING ("raw1394 - failed to get handle: %s.\n", strerror (errno));
+ continue;
+ }
+ if (raw1394_get_port_info (handle, pinf, 16) < 0) {
+ GST_WARNING ("raw1394 - failed to get port info: %s.\n",
+ strerror (errno));
+ goto next;
+ }
+
+ /* tell raw1394 which host adapter to use */
+ if (raw1394_set_port (handle, j) < 0) {
+ GST_WARNING ("raw1394 - failed to set set port: %s.\n", strerror (errno));
+ goto next;
+ }
+
+ /* now loop over all the nodes */
+ for (i = 0; i < raw1394_get_nodecount (handle); i++) {
+ /* are we looking for an explicit GUID ? */
+ if (src->guid != 0) {
+ if (src->guid == rom1394_get_guid (handle, i)) {
+ node = i;
+ src->port = j;
+ g_free (src->uri);
+ src->uri = g_strdup_printf ("dv://%d", src->port);
+ break;
+ }
+ } else {
+ rom1394_directory rom_dir;
+
+ /* select first AV/C Tape Recorder Player node */
+ if (rom1394_get_directory (handle, i, &rom_dir) < 0) {
+ GST_WARNING ("error reading config rom directory for node %d\n", i);
+ continue;
+ }
+ if ((rom1394_get_node_type (&rom_dir) == ROM1394_NODE_TYPE_AVC) &&
+ avc1394_check_subunit_type (handle, i, AVC1394_SUBUNIT_TYPE_VCR)) {
+ node = i;
+ src->port = j;
+ src->guid = rom1394_get_guid (handle, i);
+ g_free (src->uri);
+ src->uri = g_strdup_printf ("dv://%d", src->port);
+ g_free (src->device_name);
+ src->device_name = g_strdup (rom_dir.label);
+ break;
+ }
+ rom1394_free_directory (&rom_dir);
+ }
+ }
+ next:
+ raw1394_destroy_handle (handle);
+ }
+ return node;
+}
+
+static gboolean
+gst_dv1394src_start (GstBaseSrc * bsrc)
+{
+ GstDV1394Src *src = GST_DV1394SRC (bsrc);
+ int control_sock[2];
+
+ src->connected = FALSE;
+
+ if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
+ goto socket_pair;
+
+ READ_SOCKET (src) = control_sock[0];
+ WRITE_SOCKET (src) = control_sock[1];
+
+ fcntl (READ_SOCKET (src), F_SETFL, O_NONBLOCK);
+ fcntl (WRITE_SOCKET (src), F_SETFL, O_NONBLOCK);
+
+ src->handle = raw1394_new_handle ();
+
+ if (!src->handle) {
+ if (errno == EACCES)
+ goto permission_denied;
+ else if (errno == ENOENT)
+ goto not_found;
+ else
+ goto no_handle;
+ }
+
+ src->num_ports = raw1394_get_port_info (src->handle, src->pinfo, 16);
+
+ if (src->num_ports == 0)
+ goto no_ports;
+
+ if (src->use_avc || src->port == -1)
+ src->avc_node = gst_dv1394src_discover_avc_node (src);
+
+ /* lets destroy handle and create one on port
+ this is more reliable than setting port on
+ the existing handle */
+ raw1394_destroy_handle (src->handle);
+ src->handle = raw1394_new_handle_on_port (src->port);
+ if (!src->handle)
+ goto cannot_set_port;
+
+ raw1394_set_userdata (src->handle, src);
+ raw1394_set_bus_reset_handler (src->handle, gst_dv1394src_bus_reset);
+
+#ifdef HAVE_LIBIEC61883
+ if ((src->iec61883dv =
+ iec61883_dv_fb_init (src->handle,
+ gst_dv1394src_iec61883_receive, src)) == NULL)
+ goto cannot_initialise_dv;
+
+#else
+ raw1394_set_iso_handler (src->handle, src->channel,
+ gst_dv1394src_iso_receive);
+#endif
+
+ GST_DEBUG_OBJECT (src, "successfully opened up 1394 connection");
+ src->connected = TRUE;
+
+#ifdef HAVE_LIBIEC61883
+ if (iec61883_dv_fb_start (src->iec61883dv, src->channel) != 0)
+ goto cannot_start;
+#else
+ if (raw1394_start_iso_rcv (src->handle, src->channel) < 0)
+ goto cannot_start;
+#endif
+
+ if (src->use_avc) {
+ raw1394handle_t avc_handle = raw1394_new_handle_on_port (src->port);
+
+ /* start the VCR */
+ if (avc_handle) {
+ if (!avc1394_vcr_is_recording (avc_handle, src->avc_node)
+ && avc1394_vcr_is_playing (avc_handle, src->avc_node)
+ != AVC1394_VCR_OPERAND_PLAY_FORWARD)
+ avc1394_vcr_play (avc_handle, src->avc_node);
+ raw1394_destroy_handle (avc_handle);
+ } else {
+ GST_WARNING_OBJECT (src, "Starting VCR via avc1394 failed: %s",
+ g_strerror (errno));
+ }
+ }
+
+ gst_1394_clock_set_handle (src->provided_clock, src->handle);
+
+ return TRUE;
+
+socket_pair:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
+ GST_ERROR_SYSTEM);
+ return FALSE;
+ }
+permission_denied:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
+not_found:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
+no_handle:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+ ("can't get raw1394 handle (%s)", g_strerror (errno)));
+ return FALSE;
+ }
+no_ports:
+ {
+ raw1394_destroy_handle (src->handle);
+ src->handle = NULL;
+ GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
+ ("no ports available for raw1394"));
+ return FALSE;
+ }
+cannot_set_port:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+ ("can't set 1394 port %d", src->port));
+ return FALSE;
+ }
+cannot_start:
+ {
+ raw1394_destroy_handle (src->handle);
+ src->handle = NULL;
+#ifdef HAVE_LIBIEC61883
+ iec61883_dv_fb_close (src->iec61883dv);
+ src->iec61883dv = NULL;
+#endif
+ GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+ ("can't start 1394 iso receive"));
+ return FALSE;
+ }
+#ifdef HAVE_LIBIEC61883
+cannot_initialise_dv:
+ {
+ raw1394_destroy_handle (src->handle);
+ src->handle = NULL;
+ GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+ ("can't initialise iec61883 dv"));
+ return FALSE;
+ }
+#endif
+}
+
+static gboolean
+gst_dv1394src_stop (GstBaseSrc * bsrc)
+{
+ GstDV1394Src *src = GST_DV1394SRC (bsrc);
+
+ close (READ_SOCKET (src));
+ close (WRITE_SOCKET (src));
+ READ_SOCKET (src) = -1;
+ WRITE_SOCKET (src) = -1;
+#ifdef HAVE_LIBIEC61883
+ iec61883_dv_fb_close (src->iec61883dv);
+#else
+ raw1394_stop_iso_rcv (src->handle, src->channel);
+#endif
+
+ if (src->use_avc) {
+ raw1394handle_t avc_handle = raw1394_new_handle_on_port (src->port);
+
+ /* pause and stop the VCR */
+ if (avc_handle) {
+ if (!avc1394_vcr_is_recording (avc_handle, src->avc_node)
+ && (avc1394_vcr_is_playing (avc_handle, src->avc_node)
+ != AVC1394_VCR_OPERAND_PLAY_FORWARD_PAUSE))
+ avc1394_vcr_pause (avc_handle, src->avc_node);
+ avc1394_vcr_stop (avc_handle, src->avc_node);
+ raw1394_destroy_handle (avc_handle);
+ } else {
+ GST_WARNING_OBJECT (src, "Starting VCR via avc1394 failed: %s",
+ g_strerror (errno));
+ }
+ }
+
+ gst_1394_clock_unset_handle (src->provided_clock);
+
+ raw1394_destroy_handle (src->handle);
+
+ return TRUE;
+}
+
+static gboolean
+gst_dv1394src_unlock (GstBaseSrc * bsrc)
+{
+ GstDV1394Src *src = GST_DV1394SRC (bsrc);
+
+ SEND_COMMAND (src, CONTROL_STOP);
+
+ return TRUE;
+}
+
+static gboolean
+gst_dv1394src_query (GstBaseSrc * basesrc, GstQuery * query)
+{
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_LATENCY:
+ {
+ gst_query_set_latency (query, TRUE, GST_SECOND / 25, GST_CLOCK_TIME_NONE);
+ }
+ break;
+ default:
+ goto not_supported;
+ }
+
+ return TRUE;
+
+not_supported:
+ return GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
+}
+
+static void
+gst_dv1394src_update_device_name (GstDV1394Src * src)
+{
+ raw1394handle_t handle;
+ gint portcount, port, nodecount, node;
+ rom1394_directory directory;
+
+ g_free (src->device_name);
+ src->device_name = NULL;
+
+ GST_LOG_OBJECT (src, "updating device name for current GUID");
+
+ handle = raw1394_new_handle ();
+
+ if (handle == NULL)
+ goto gethandle_failed;
+
+ portcount = raw1394_get_port_info (handle, NULL, 0);
+ for (port = 0; port < portcount; port++) {
+ if (raw1394_set_port (handle, port) >= 0) {
+ nodecount = raw1394_get_nodecount (handle);
+ for (node = 0; node < nodecount; node++) {
+ if (src->guid == rom1394_get_guid (handle, node)) {
+ if (rom1394_get_directory (handle, node, &directory) >= 0) {
+ g_free (src->device_name);
+ src->device_name = g_strdup (directory.label);
+ rom1394_free_directory (&directory);
+ goto done;
+ } else {
+ GST_WARNING ("error reading rom directory for node %d", node);
+ }
+ }
+ }
+ }
+ }
+
+ src->device_name = g_strdup ("Unknown"); /* FIXME: translate? */
+
+done:
+
+ raw1394_destroy_handle (handle);
+ return;
+
+/* ERRORS */
+gethandle_failed:
+ {
+ GST_WARNING ("failed to get raw1394 handle: %s", g_strerror (errno));
+ src->device_name = g_strdup ("Unknown"); /* FIXME: translate? */
+ return;
+ }
+}
+
+/*** GSTURIHANDLER INTERFACE *************************************************/
+
+static guint
+gst_dv1394src_uri_get_type (void)
+{
+ return GST_URI_SRC;
+}
+
+static gchar **
+gst_dv1394src_uri_get_protocols (void)
+{
+ static gchar *protocols[] = { (char *) "dv", NULL };
+
+ return protocols;
+}
+
+static const gchar *
+gst_dv1394src_uri_get_uri (GstURIHandler * handler)
+{
+ GstDV1394Src *gst_dv1394src = GST_DV1394SRC (handler);
+
+ return gst_dv1394src->uri;
+}
+
+static gboolean
+gst_dv1394src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+{
+ gchar *protocol, *location;
+ gboolean ret = TRUE;
+ GstDV1394Src *gst_dv1394src = GST_DV1394SRC (handler);
+
+ protocol = gst_uri_get_protocol (uri);
+ if (strcmp (protocol, "dv") != 0) {
+ g_free (protocol);
+ return FALSE;
+ }
+ g_free (protocol);
+
+ location = gst_uri_get_location (uri);
+ if (location && *location != '\0')
+ gst_dv1394src->port = strtol (location, NULL, 10);
+ else
+ gst_dv1394src->port = DEFAULT_PORT;
+ g_free (location);
+ g_free (gst_dv1394src->uri);
+ gst_dv1394src->uri = g_strdup_printf ("dv://%d", gst_dv1394src->port);
+
+ return ret;
+}
+
+static void
+gst_dv1394src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+ GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+ iface->get_type = gst_dv1394src_uri_get_type;
+ iface->get_protocols = gst_dv1394src_uri_get_protocols;
+ iface->get_uri = gst_dv1394src_uri_get_uri;
+ iface->set_uri = gst_dv1394src_uri_set_uri;
+}
diff --git a/ext/raw1394/gstdv1394src.h b/ext/raw1394/gstdv1394src.h
new file mode 100644
index 0000000..bf9a3e0
--- /dev/null
+++ b/ext/raw1394/gstdv1394src.h
@@ -0,0 +1,101 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_GST1394_H__
+#define __GST_GST1394_H__
+
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+#include "gst1394clock.h"
+
+#include <libraw1394/raw1394.h>
+#ifdef HAVE_LIBIEC61883
+#include <libiec61883/iec61883.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DV1394SRC \
+ (gst_dv1394src_get_type())
+#define GST_DV1394SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DV1394SRC,GstDV1394Src))
+#define GST_DV1394SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DV1394SRC,GstDV1394SrcClass))
+#define GST_IS_DV1394SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DV1394SRC))
+#define GST_IS_DV1394SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DV1394SRC))
+
+typedef struct _GstDV1394Src GstDV1394Src;
+typedef struct _GstDV1394SrcClass GstDV1394SrcClass;
+
+struct _GstDV1394Src {
+ GstPushSrc element;
+
+ // consecutive=2, skip=4 will skip 4 frames, then let 2 consecutive ones thru
+ gint consecutive;
+ gint skip;
+ gboolean drop_incomplete;
+
+ gint num_ports;
+ gint port;
+ gint channel;
+ octlet_t guid;
+ gint avc_node;
+ gboolean use_avc;
+
+ struct raw1394_portinfo pinfo[16];
+ raw1394handle_t handle;
+
+ GstBuffer *buf;
+
+ GstBuffer *frame;
+ guint frame_size;
+ guint frame_rate;
+ guint bytes_in_frame;
+ guint frame_sequence;
+
+ int control_sock[2];
+
+ gchar *uri;
+
+ gchar *device_name;
+
+ gboolean connected;
+ #ifdef HAVE_LIBIEC61883
+ iec61883_dv_fb_t iec61883dv;
+ #endif
+
+ Gst1394Clock *provided_clock;
+};
+
+struct _GstDV1394SrcClass {
+ GstPushSrcClass parent_class;
+
+ /* signal */
+ void (*frame_dropped) (GstElement *elem);
+};
+
+GType gst_dv1394src_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_GST1394_H__ */
diff --git a/ext/raw1394/gsthdv1394src.c b/ext/raw1394/gsthdv1394src.c
new file mode 100644
index 0000000..33ef11e
--- /dev/null
+++ b/ext/raw1394/gsthdv1394src.c
@@ -0,0 +1,844 @@
+/* GStreamer
+ * Copyright (C) <2008> Edward Hervey <bilboed@bilboed.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:element-hdv1394src
+ *
+ * Read MPEG-TS data from firewire port.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch hdv1394src ! queue ! decodebin name=d ! queue ! xvimagesink d. ! queue ! alsasink
+ * ]| captures from the firewire port and plays the streams.
+ * |[
+ * gst-launch hdv1394src ! queue ! filesink location=mydump.ts
+ * ]| capture to a disk file
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <libavc1394/avc1394.h>
+#include <libavc1394/avc1394_vcr.h>
+#include <libavc1394/rom1394.h>
+#include <libraw1394/raw1394.h>
+#include <libiec61883/iec61883.h>
+
+#include <gst/gst.h>
+
+#include "gsthdv1394src.h"
+#include "gst1394probe.h"
+
+
+#define CONTROL_STOP 'S' /* stop the select call */
+#define CONTROL_SOCKETS(src) src->control_sock
+#define WRITE_SOCKET(src) src->control_sock[1]
+#define READ_SOCKET(src) src->control_sock[0]
+
+#define SEND_COMMAND(src, command) \
+G_STMT_START { \
+ int G_GNUC_UNUSED _res; unsigned char c; c = command; \
+ _res = write (WRITE_SOCKET(src), &c, 1); \
+} G_STMT_END
+
+#define READ_COMMAND(src, command, res) \
+G_STMT_START { \
+ res = read(READ_SOCKET(src), &command, 1); \
+} G_STMT_END
+
+
+GST_DEBUG_CATEGORY_STATIC (hdv1394src_debug);
+#define GST_CAT_DEFAULT (hdv1394src_debug)
+
+#define DEFAULT_PORT -1
+#define DEFAULT_CHANNEL 63
+#define DEFAULT_USE_AVC TRUE
+#define DEFAULT_GUID 0
+
+enum
+{
+ PROP_0,
+ PROP_PORT,
+ PROP_CHANNEL,
+ PROP_USE_AVC,
+ PROP_GUID,
+ PROP_DEVICE_NAME
+};
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS
+ ("video/mpegts,systemstream=(boolean)true,packetsize=(int)188")
+ );
+
+static void gst_hdv1394src_uri_handler_init (gpointer g_iface,
+ gpointer iface_data);
+
+static void gst_hdv1394src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_hdv1394src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_hdv1394src_dispose (GObject * object);
+
+static gboolean gst_hdv1394src_start (GstBaseSrc * bsrc);
+static gboolean gst_hdv1394src_stop (GstBaseSrc * bsrc);
+static gboolean gst_hdv1394src_unlock (GstBaseSrc * bsrc);
+
+static GstFlowReturn gst_hdv1394src_create (GstPushSrc * psrc,
+ GstBuffer ** buf);
+
+static void gst_hdv1394src_update_device_name (GstHDV1394Src * src);
+
+static void
+_do_init (GType type)
+{
+ static const GInterfaceInfo urihandler_info = {
+ gst_hdv1394src_uri_handler_init,
+ NULL,
+ NULL,
+ };
+ g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
+
+ gst_1394_type_add_property_probe_interface (type);
+
+ GST_DEBUG_CATEGORY_INIT (hdv1394src_debug, "hdv1394src", 0,
+ "MPEG-TS firewire source");
+}
+
+GST_BOILERPLATE_FULL (GstHDV1394Src, gst_hdv1394src, GstPushSrc,
+ GST_TYPE_PUSH_SRC, _do_init);
+
+
+static void
+gst_hdv1394src_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class, &src_factory);
+
+ gst_element_class_set_details_simple (element_class,
+ "Firewire (1394) HDV video source", "Source/Video",
+ "Source for MPEG-TS video data from firewire port",
+ "Edward Hervey <bilboed@bilboed.com>");
+}
+
+static void
+gst_hdv1394src_class_init (GstHDV1394SrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstBaseSrcClass *gstbasesrc_class;
+ GstPushSrcClass *gstpushsrc_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstbasesrc_class = (GstBaseSrcClass *) klass;
+ gstpushsrc_class = (GstPushSrcClass *) klass;
+
+ gobject_class->set_property = gst_hdv1394src_set_property;
+ gobject_class->get_property = gst_hdv1394src_get_property;
+ gobject_class->dispose = gst_hdv1394src_dispose;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
+ g_param_spec_int ("port", "Port", "Port number (-1 automatic)",
+ -1, 16, DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CHANNEL,
+ g_param_spec_int ("channel", "Channel", "Channel number for listening",
+ 0, 64, DEFAULT_CHANNEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_USE_AVC,
+ g_param_spec_boolean ("use-avc", "Use AV/C", "Use AV/C VTR control",
+ DEFAULT_USE_AVC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GUID,
+ g_param_spec_uint64 ("guid", "GUID",
+ "select one of multiple DV devices by its GUID. use a hexadecimal "
+ "like 0xhhhhhhhhhhhhhhhh. (0 = no guid)", 0, G_MAXUINT64,
+ DEFAULT_GUID, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstHDV1394Src:device-name
+ *
+ * Descriptive name of the currently opened device
+ *
+ * Since: 0.10.7
+ **/
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEVICE_NAME,
+ g_param_spec_string ("device-name", "device name",
+ "user-friendly name of the device", "Default",
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ gstbasesrc_class->negotiate = NULL;
+ gstbasesrc_class->start = gst_hdv1394src_start;
+ gstbasesrc_class->stop = gst_hdv1394src_stop;
+ gstbasesrc_class->unlock = gst_hdv1394src_unlock;
+
+ gstpushsrc_class->create = gst_hdv1394src_create;
+}
+
+static void
+gst_hdv1394src_init (GstHDV1394Src * dv1394src, GstHDV1394SrcClass * klass)
+{
+ GstPad *srcpad = GST_BASE_SRC_PAD (dv1394src);
+
+ gst_base_src_set_live (GST_BASE_SRC (dv1394src), TRUE);
+ gst_pad_use_fixed_caps (srcpad);
+
+ dv1394src->port = DEFAULT_PORT;
+ dv1394src->channel = DEFAULT_CHANNEL;
+
+ dv1394src->use_avc = DEFAULT_USE_AVC;
+ dv1394src->guid = DEFAULT_GUID;
+ dv1394src->uri = g_strdup_printf ("hdv://%d", dv1394src->port);
+ dv1394src->device_name = g_strdup_printf ("Default");
+
+ READ_SOCKET (dv1394src) = -1;
+ WRITE_SOCKET (dv1394src) = -1;
+
+ dv1394src->frame_sequence = 0;
+}
+
+static void
+gst_hdv1394src_dispose (GObject * object)
+{
+ GstHDV1394Src *src = GST_HDV1394SRC (object);
+
+ g_free (src->uri);
+ src->uri = NULL;
+
+ g_free (src->device_name);
+ src->device_name = NULL;
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_hdv1394src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstHDV1394Src *filter = GST_HDV1394SRC (object);
+
+ switch (prop_id) {
+ case PROP_PORT:
+ filter->port = g_value_get_int (value);
+ g_free (filter->uri);
+ filter->uri = g_strdup_printf ("hdv://%d", filter->port);
+ break;
+ case PROP_CHANNEL:
+ filter->channel = g_value_get_int (value);
+ break;
+ case PROP_USE_AVC:
+ filter->use_avc = g_value_get_boolean (value);
+ break;
+ case PROP_GUID:
+ filter->guid = g_value_get_uint64 (value);
+ gst_hdv1394src_update_device_name (filter);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_hdv1394src_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstHDV1394Src *filter = GST_HDV1394SRC (object);
+
+ switch (prop_id) {
+ case PROP_PORT:
+ g_value_set_int (value, filter->port);
+ break;
+ case PROP_CHANNEL:
+ g_value_set_int (value, filter->channel);
+ break;
+ case PROP_USE_AVC:
+ g_value_set_boolean (value, filter->use_avc);
+ break;
+ case PROP_GUID:
+ g_value_set_uint64 (value, filter->guid);
+ break;
+ case PROP_DEVICE_NAME:
+ g_value_set_string (value, filter->device_name);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstHDV1394Src *
+gst_hdv1394src_from_raw1394handle (raw1394handle_t handle)
+{
+ iec61883_mpeg2_t mpeg2 = (iec61883_mpeg2_t) raw1394_get_userdata (handle);
+ return GST_HDV1394SRC (iec61883_mpeg2_get_callback_data (mpeg2));
+}
+
+/* Within one loop iteration (which may call _receive() many times), it seems
+ * as though '*data' will always be different.
+ *
+ * We can therefore assume that any '*data' given to us will stay allocated until
+ * the next loop iteration.
+ */
+
+static int
+gst_hdv1394src_iec61883_receive (unsigned char *data, int len,
+ unsigned int dropped, void *cbdata)
+{
+ GstHDV1394Src *dv1394src = GST_HDV1394SRC (cbdata);
+
+ GST_LOG ("data:%p, len:%d, dropped:%d", data, len, dropped);
+
+ /* error out if we don't have enough room ! */
+ if (G_UNLIKELY (dv1394src->outoffset > (2048 * 188 - len)))
+ return -1;
+
+ if (G_LIKELY (len == IEC61883_MPEG2_TSP_SIZE)) {
+ memcpy ((guint8 *) dv1394src->outdata + dv1394src->outoffset, data, len);
+ dv1394src->outoffset += len;
+ }
+ dv1394src->frame_sequence++;
+ return 0;
+}
+
+/*
+ * When an ieee1394 bus reset happens, usually a device has been removed
+ * or added. We send a message on the message bus with the node count
+ * and whether the capture device used in this element connected, disconnected
+ * or was unchanged
+ * Message structure:
+ * nodecount - integer with number of nodes on bus
+ * current-device-change - integer (1 if device connected, 0 if no change to
+ * current device status, -1 if device disconnected)
+ */
+static int
+gst_hdv1394src_bus_reset (raw1394handle_t handle, unsigned int generation)
+{
+ GstHDV1394Src *src;
+ gint nodecount;
+ GstMessage *message;
+ GstStructure *structure;
+ gint current_device_change;
+ gint i;
+
+ src = gst_hdv1394src_from_raw1394handle (handle);
+
+ GST_INFO_OBJECT (src, "have bus reset");
+
+ /* update generation - told to do so by docs */
+ raw1394_update_generation (handle, generation);
+ nodecount = raw1394_get_nodecount (handle);
+ /* allocate memory for portinfo */
+
+ /* current_device_change is -1 if camera disconnected, 0 if other device
+ * connected or 1 if camera has now connected */
+ current_device_change = -1;
+ for (i = 0; i < nodecount; i++) {
+ if (src->guid == rom1394_get_guid (handle, i)) {
+ /* Camera is with us */
+ GST_DEBUG ("Camera is with us");
+ if (!src->connected) {
+ current_device_change = 1;
+ src->connected = TRUE;
+ } else
+ current_device_change = 0;
+ }
+ }
+ if (src->connected && current_device_change == -1) {
+ GST_DEBUG ("Camera has disconnected");
+ src->connected = FALSE;
+ } else if (!src->connected && current_device_change == -1) {
+ GST_DEBUG ("Camera is still not with us");
+ current_device_change = 0;
+ }
+
+ structure = gst_structure_new ("ieee1394-bus-reset", "nodecount", G_TYPE_INT,
+ nodecount, "current-device-change", G_TYPE_INT, current_device_change,
+ NULL);
+ message = gst_message_new_element (GST_OBJECT (src), structure);
+ gst_element_post_message (GST_ELEMENT (src), message);
+
+ return 0;
+}
+
+static GstFlowReturn
+gst_hdv1394src_create (GstPushSrc * psrc, GstBuffer ** buf)
+{
+ GstHDV1394Src *dv1394src = GST_HDV1394SRC (psrc);
+ GstCaps *caps;
+ struct pollfd pollfds[2];
+
+ pollfds[0].fd = raw1394_get_fd (dv1394src->handle);
+ pollfds[0].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
+ pollfds[1].fd = READ_SOCKET (dv1394src);
+ pollfds[1].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
+
+ /* allocate a 2048 samples buffer */
+ dv1394src->outdata = g_malloc (2048 * 188);
+ dv1394src->outoffset = 0;
+
+ GST_DEBUG ("Create...");
+
+ while (TRUE) {
+ int res = poll (pollfds, 2, -1);
+
+ GST_LOG ("res:%d", res);
+
+ if (G_UNLIKELY (res < 0)) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ else
+ goto error_while_polling;
+ }
+
+ if (G_UNLIKELY (pollfds[1].revents)) {
+ char command;
+
+ if (pollfds[1].revents & POLLIN)
+ READ_COMMAND (dv1394src, command, res);
+
+ goto told_to_stop;
+ } else if (G_LIKELY (pollfds[0].revents & POLLIN)) {
+ int pt;
+
+ pt = dv1394src->frame_sequence;
+ /* shouldn't block in theory */
+ GST_LOG ("Iterating ! (%d)", dv1394src->frame_sequence);
+ raw1394_loop_iterate (dv1394src->handle);
+ GST_LOG ("After iteration : %d (diff:%d)",
+ dv1394src->frame_sequence, dv1394src->frame_sequence - pt);
+ if (dv1394src->outoffset)
+ break;
+ }
+ }
+
+ g_assert (dv1394src->outoffset);
+
+ GST_LOG ("We have some frames (%u bytes)", (guint) dv1394src->outoffset);
+
+ /* Create the buffer */
+ *buf = gst_buffer_new ();
+ GST_BUFFER_DATA (*buf) = dv1394src->outdata;
+ GST_BUFFER_MALLOCDATA (*buf) = dv1394src->outdata;
+ GST_BUFFER_SIZE (*buf) = dv1394src->outoffset;
+ dv1394src->outdata = NULL;
+ dv1394src->outoffset = 0;
+
+ caps = gst_pad_get_caps (GST_BASE_SRC_PAD (psrc));
+ gst_buffer_set_caps (*buf, caps);
+ gst_caps_unref (caps);
+
+ return GST_FLOW_OK;
+
+error_while_polling:
+ {
+ GST_ELEMENT_ERROR (dv1394src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
+ return GST_FLOW_UNEXPECTED;
+ }
+told_to_stop:
+ {
+ GST_DEBUG_OBJECT (dv1394src, "told to stop, shutting down");
+ return GST_FLOW_WRONG_STATE;
+ }
+}
+
+static int
+gst_hdv1394src_discover_avc_node (GstHDV1394Src * src)
+{
+ int node = -1;
+ int i, j = 0;
+ int m = src->num_ports;
+
+ if (src->port >= 0) {
+ /* search on explicit port */
+ j = src->port;
+ m = j + 1;
+ }
+
+ /* loop over all our ports */
+ for (; j < m && node == -1; j++) {
+ raw1394handle_t handle;
+ struct raw1394_portinfo pinf[16];
+
+ /* open the port */
+ handle = raw1394_new_handle ();
+ if (!handle) {
+ GST_WARNING ("raw1394 - failed to get handle: %s.\n", strerror (errno));
+ continue;
+ }
+ if (raw1394_get_port_info (handle, pinf, 16) < 0) {
+ GST_WARNING ("raw1394 - failed to get port info: %s.\n",
+ strerror (errno));
+ goto next;
+ }
+
+ /* tell raw1394 which host adapter to use */
+ if (raw1394_set_port (handle, j) < 0) {
+ GST_WARNING ("raw1394 - failed to set set port: %s.\n", strerror (errno));
+ goto next;
+ }
+
+ /* now loop over all the nodes */
+ for (i = 0; i < raw1394_get_nodecount (handle); i++) {
+ /* are we looking for an explicit GUID ? */
+ if (src->guid != 0) {
+ if (src->guid == rom1394_get_guid (handle, i)) {
+ node = i;
+ src->port = j;
+ g_free (src->uri);
+ src->uri = g_strdup_printf ("dv://%d", src->port);
+ break;
+ }
+ } else {
+ rom1394_directory rom_dir;
+
+ /* select first AV/C Tape Recorder Player node */
+ if (rom1394_get_directory (handle, i, &rom_dir) < 0) {
+ GST_WARNING ("error reading config rom directory for node %d\n", i);
+ continue;
+ }
+ if ((rom1394_get_node_type (&rom_dir) == ROM1394_NODE_TYPE_AVC) &&
+ avc1394_check_subunit_type (handle, i, AVC1394_SUBUNIT_TYPE_VCR)) {
+ node = i;
+ src->port = j;
+ src->guid = rom1394_get_guid (handle, i);
+ g_free (src->uri);
+ src->uri = g_strdup_printf ("dv://%d", src->port);
+ g_free (src->device_name);
+ src->device_name = g_strdup (rom_dir.label);
+ break;
+ }
+ rom1394_free_directory (&rom_dir);
+ }
+ }
+ next:
+ raw1394_destroy_handle (handle);
+ }
+ return node;
+}
+
+static gboolean
+gst_hdv1394src_start (GstBaseSrc * bsrc)
+{
+ GstHDV1394Src *src = GST_HDV1394SRC (bsrc);
+ int control_sock[2];
+
+ src->connected = FALSE;
+
+ if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
+ goto socket_pair;
+
+ READ_SOCKET (src) = control_sock[0];
+ WRITE_SOCKET (src) = control_sock[1];
+
+ fcntl (READ_SOCKET (src), F_SETFL, O_NONBLOCK);
+ fcntl (WRITE_SOCKET (src), F_SETFL, O_NONBLOCK);
+
+ src->handle = raw1394_new_handle ();
+
+ if (!src->handle) {
+ if (errno == EACCES)
+ goto permission_denied;
+ else if (errno == ENOENT)
+ goto not_found;
+ else
+ goto no_handle;
+ }
+
+ src->num_ports = raw1394_get_port_info (src->handle, src->pinfo, 16);
+
+ if (src->num_ports == 0)
+ goto no_ports;
+
+ if (src->use_avc || src->port == -1)
+ src->avc_node = gst_hdv1394src_discover_avc_node (src);
+
+ /* lets destroy handle and create one on port
+ this is more reliable than setting port on
+ the existing handle */
+ raw1394_destroy_handle (src->handle);
+ src->handle = raw1394_new_handle_on_port (src->port);
+ if (!src->handle)
+ goto cannot_set_port;
+
+ raw1394_set_userdata (src->handle, src);
+ raw1394_set_bus_reset_handler (src->handle, gst_hdv1394src_bus_reset);
+
+ if ((src->iec61883mpeg2 =
+ iec61883_mpeg2_recv_init (src->handle,
+ gst_hdv1394src_iec61883_receive, src)) == NULL)
+ goto cannot_initialise_dv;
+
+#if 0
+ raw1394_set_iso_handler (src->handle, src->channel,
+ gst_hdv1394src_iso_receive);
+#endif
+
+ GST_DEBUG_OBJECT (src, "successfully opened up 1394 connection");
+ src->connected = TRUE;
+
+ if (iec61883_mpeg2_recv_start (src->iec61883mpeg2, src->channel) != 0)
+ goto cannot_start;
+#if 0
+ if (raw1394_start_iso_rcv (src->handle, src->channel) < 0)
+ goto cannot_start;
+#endif
+
+ if (src->use_avc) {
+ raw1394handle_t avc_handle = raw1394_new_handle_on_port (src->port);
+
+ GST_LOG ("We have an avc_handle");
+
+ /* start the VCR */
+ if (avc_handle) {
+ if (!avc1394_vcr_is_recording (avc_handle, src->avc_node)
+ && avc1394_vcr_is_playing (avc_handle, src->avc_node)
+ != AVC1394_VCR_OPERAND_PLAY_FORWARD) {
+ GST_LOG ("Calling avc1394_vcr_play()");
+ avc1394_vcr_play (avc_handle, src->avc_node);
+ }
+ raw1394_destroy_handle (avc_handle);
+ } else {
+ GST_WARNING_OBJECT (src, "Starting VCR via avc1394 failed: %s",
+ g_strerror (errno));
+ }
+ }
+
+ return TRUE;
+
+socket_pair:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
+ GST_ERROR_SYSTEM);
+ return FALSE;
+ }
+permission_denied:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
+not_found:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
+no_handle:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
+ ("can't get raw1394 handle (%s)", g_strerror (errno)));
+ return FALSE;
+ }
+no_ports:
+ {
+ raw1394_destroy_handle (src->handle);
+ src->handle = NULL;
+ GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
+ ("no ports available for raw1394"));
+ return FALSE;
+ }
+cannot_set_port:
+ {
+ GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
+ ("can't set 1394 port %d", src->port));
+ return FALSE;
+ }
+cannot_start:
+ {
+ raw1394_destroy_handle (src->handle);
+ src->handle = NULL;
+ iec61883_mpeg2_close (src->iec61883mpeg2);
+ src->iec61883mpeg2 = NULL;
+ GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+ ("can't start 1394 iso receive"));
+ return FALSE;
+ }
+cannot_initialise_dv:
+ {
+ raw1394_destroy_handle (src->handle);
+ src->handle = NULL;
+ GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
+ ("can't initialise iec61883 hdv"));
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_hdv1394src_stop (GstBaseSrc * bsrc)
+{
+ GstHDV1394Src *src = GST_HDV1394SRC (bsrc);
+
+ close (READ_SOCKET (src));
+ close (WRITE_SOCKET (src));
+ READ_SOCKET (src) = -1;
+ WRITE_SOCKET (src) = -1;
+
+ iec61883_mpeg2_close (src->iec61883mpeg2);
+#if 0
+ raw1394_stop_iso_rcv (src->handle, src->channel);
+#endif
+
+ if (src->use_avc) {
+ raw1394handle_t avc_handle = raw1394_new_handle_on_port (src->port);
+
+ /* pause and stop the VCR */
+ if (avc_handle) {
+ if (!avc1394_vcr_is_recording (avc_handle, src->avc_node)
+ && (avc1394_vcr_is_playing (avc_handle, src->avc_node)
+ != AVC1394_VCR_OPERAND_PLAY_FORWARD_PAUSE))
+ avc1394_vcr_pause (avc_handle, src->avc_node);
+ avc1394_vcr_stop (avc_handle, src->avc_node);
+ raw1394_destroy_handle (avc_handle);
+ } else {
+ GST_WARNING_OBJECT (src, "Starting VCR via avc1394 failed: %s",
+ g_strerror (errno));
+ }
+ }
+
+ raw1394_destroy_handle (src->handle);
+
+ return TRUE;
+}
+
+static gboolean
+gst_hdv1394src_unlock (GstBaseSrc * bsrc)
+{
+ GstHDV1394Src *src = GST_HDV1394SRC (bsrc);
+
+ SEND_COMMAND (src, CONTROL_STOP);
+
+ return TRUE;
+}
+
+static void
+gst_hdv1394src_update_device_name (GstHDV1394Src * src)
+{
+ raw1394handle_t handle;
+ gint portcount, port, nodecount, node;
+ rom1394_directory directory;
+
+ g_free (src->device_name);
+ src->device_name = NULL;
+
+ GST_LOG_OBJECT (src, "updating device name for current GUID");
+
+ handle = raw1394_new_handle ();
+
+ if (handle == NULL)
+ goto gethandle_failed;
+
+ portcount = raw1394_get_port_info (handle, NULL, 0);
+ for (port = 0; port < portcount; port++) {
+ if (raw1394_set_port (handle, port) >= 0) {
+ nodecount = raw1394_get_nodecount (handle);
+ for (node = 0; node < nodecount; node++) {
+ if (src->guid == rom1394_get_guid (handle, node)) {
+ if (rom1394_get_directory (handle, node, &directory) >= 0) {
+ g_free (src->device_name);
+ src->device_name = g_strdup (directory.label);
+ rom1394_free_directory (&directory);
+ goto done;
+ } else {
+ GST_WARNING ("error reading rom directory for node %d", node);
+ }
+ }
+ }
+ }
+ }
+
+ src->device_name = g_strdup ("Unknown"); /* FIXME: translate? */
+
+done:
+
+ raw1394_destroy_handle (handle);
+ return;
+
+/* ERRORS */
+gethandle_failed:
+ {
+ GST_WARNING ("failed to get raw1394 handle: %s", g_strerror (errno));
+ src->device_name = g_strdup ("Unknown"); /* FIXME: translate? */
+ return;
+ }
+}
+
+/*** GSTURIHANDLER INTERFACE *************************************************/
+
+static guint
+gst_hdv1394src_uri_get_type (void)
+{
+ return GST_URI_SRC;
+}
+
+static gchar **
+gst_hdv1394src_uri_get_protocols (void)
+{
+ static gchar *protocols[] = { (char *) "hdv", NULL };
+
+ return protocols;
+}
+
+static const gchar *
+gst_hdv1394src_uri_get_uri (GstURIHandler * handler)
+{
+ GstHDV1394Src *gst_hdv1394src = GST_HDV1394SRC (handler);
+
+ return gst_hdv1394src->uri;
+}
+
+static gboolean
+gst_hdv1394src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+{
+ gchar *protocol, *location;
+ gboolean ret = TRUE;
+ GstHDV1394Src *gst_hdv1394src = GST_HDV1394SRC (handler);
+
+ protocol = gst_uri_get_protocol (uri);
+ if (strcmp (protocol, "hdv") != 0) {
+ g_free (protocol);
+ return FALSE;
+ }
+ g_free (protocol);
+
+ location = gst_uri_get_location (uri);
+ if (location && *location != '\0')
+ gst_hdv1394src->port = strtol (location, NULL, 10);
+ else
+ gst_hdv1394src->port = DEFAULT_PORT;
+ g_free (location);
+ g_free (gst_hdv1394src->uri);
+ gst_hdv1394src->uri = g_strdup_printf ("hdv://%d", gst_hdv1394src->port);
+
+ return ret;
+}
+
+static void
+gst_hdv1394src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+ GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+ iface->get_type = gst_hdv1394src_uri_get_type;
+ iface->get_protocols = gst_hdv1394src_uri_get_protocols;
+ iface->get_uri = gst_hdv1394src_uri_get_uri;
+ iface->set_uri = gst_hdv1394src_uri_set_uri;
+}
diff --git a/ext/raw1394/gsthdv1394src.h b/ext/raw1394/gsthdv1394src.h
new file mode 100644
index 0000000..a6014a4
--- /dev/null
+++ b/ext/raw1394/gsthdv1394src.h
@@ -0,0 +1,85 @@
+/* GStreamer
+ * Copyright (C) <2008> Edward Hervey <bilboed@bilboed.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_GSTHDV1394_H__
+#define __GST_GSTHDV1394_H__
+
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+
+#include <libraw1394/raw1394.h>
+#ifdef HAVE_LIBIEC61883
+#include <libiec61883/iec61883.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_HDV1394SRC \
+ (gst_hdv1394src_get_type())
+#define GST_HDV1394SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_HDV1394SRC,GstHDV1394Src))
+#define GST_HDV1394SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_HDV1394SRC,GstHDV1394SrcClass))
+#define GST_IS_HDV1394SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_HDV1394SRC))
+#define GST_IS_HDV1394SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_HDV1394SRC))
+
+typedef struct _GstHDV1394Src GstHDV1394Src;
+typedef struct _GstHDV1394SrcClass GstHDV1394SrcClass;
+
+struct _GstHDV1394Src {
+ GstPushSrc element;
+
+ gint num_ports;
+ gint port;
+ gint channel;
+ octlet_t guid;
+ gint avc_node;
+ gboolean use_avc;
+
+ struct raw1394_portinfo pinfo[16];
+ raw1394handle_t handle;
+
+ gpointer outdata;
+ gsize outoffset;
+ guint frame_size;
+ guint frame_sequence;
+
+ int control_sock[2];
+
+ gchar *uri;
+
+ gchar *device_name;
+
+ gboolean connected;
+ iec61883_mpeg2_t iec61883mpeg2;
+};
+
+struct _GstHDV1394SrcClass {
+ GstPushSrcClass parent_class;
+};
+
+GType gst_hdv1394src_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GST_GST1394_H__ */
diff --git a/ext/shout2/Makefile.am b/ext/shout2/Makefile.am
new file mode 100644
index 0000000..4cb3f7c
--- /dev/null
+++ b/ext/shout2/Makefile.am
@@ -0,0 +1,9 @@
+plugin_LTLIBRARIES = libgstshout2.la
+
+libgstshout2_la_SOURCES = gstshout2.c
+libgstshout2_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(SHOUT2_CFLAGS)
+libgstshout2_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(SHOUT2_LIBS)
+libgstshout2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstshout2_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstshout2.h
diff --git a/ext/shout2/Makefile.in b/ext/shout2/Makefile.in
new file mode 100644
index 0000000..cebe633
--- /dev/null
+++ b/ext/shout2/Makefile.in
@@ -0,0 +1,805 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/shout2
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstshout2_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libgstshout2_la_OBJECTS = libgstshout2_la-gstshout2.lo
+libgstshout2_la_OBJECTS = $(am_libgstshout2_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstshout2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstshout2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstshout2_la_CFLAGS) $(CFLAGS) \
+ $(libgstshout2_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstshout2_la_SOURCES)
+DIST_SOURCES = $(libgstshout2_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstshout2.la
+libgstshout2_la_SOURCES = gstshout2.c
+libgstshout2_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(SHOUT2_CFLAGS)
+libgstshout2_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(SHOUT2_LIBS)
+libgstshout2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstshout2_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = gstshout2.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/shout2/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/shout2/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstshout2.la: $(libgstshout2_la_OBJECTS) $(libgstshout2_la_DEPENDENCIES) $(EXTRA_libgstshout2_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstshout2_la_LINK) -rpath $(plugindir) $(libgstshout2_la_OBJECTS) $(libgstshout2_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstshout2_la-gstshout2.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstshout2_la-gstshout2.lo: gstshout2.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstshout2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstshout2_la_CFLAGS) $(CFLAGS) -MT libgstshout2_la-gstshout2.lo -MD -MP -MF $(DEPDIR)/libgstshout2_la-gstshout2.Tpo -c -o libgstshout2_la-gstshout2.lo `test -f 'gstshout2.c' || echo '$(srcdir)/'`gstshout2.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstshout2_la-gstshout2.Tpo $(DEPDIR)/libgstshout2_la-gstshout2.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstshout2.c' object='libgstshout2_la-gstshout2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstshout2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstshout2_la_CFLAGS) $(CFLAGS) -c -o libgstshout2_la-gstshout2.lo `test -f 'gstshout2.c' || echo '$(srcdir)/'`gstshout2.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/shout2/gstshout2.c b/ext/shout2/gstshout2.c
new file mode 100644
index 0000000..c1bfcc2
--- /dev/null
+++ b/ext/shout2/gstshout2.c
@@ -0,0 +1,852 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2006> Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) <2012> Ralph Giles <giles@mozilla.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstshout2.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include "gst/gst-i18n-plugin.h"
+
+GST_DEBUG_CATEGORY_STATIC (shout2_debug);
+#define GST_CAT_DEFAULT shout2_debug
+
+
+enum
+{
+ SIGNAL_CONNECTION_PROBLEM, /* 0.11 FIXME: remove this */
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0,
+ ARG_IP, /* the ip of the server */
+ ARG_PORT, /* the encoder port number on the server */
+ ARG_PASSWORD, /* the encoder password on the server */
+ ARG_USERNAME, /* the encoder username on the server */
+ ARG_PUBLIC, /* is this stream public? */
+ ARG_STREAMNAME, /* Name of the stream */
+ ARG_DESCRIPTION, /* Description of the stream */
+ ARG_GENRE, /* Genre of the stream */
+
+ ARG_PROTOCOL, /* Protocol to connect with */
+
+ ARG_MOUNT, /* mountpoint of stream (icecast only) */
+ ARG_URL /* Url of stream (I'm guessing) */
+};
+
+#define DEFAULT_IP "127.0.0.1"
+#define DEFAULT_PORT 8000
+#define DEFAULT_PASSWORD "hackme"
+#define DEFAULT_USERNAME "source"
+#define DEFAULT_PUBLIC FALSE
+#define DEFAULT_STREAMNAME ""
+#define DEFAULT_DESCRIPTION ""
+#define DEFAULT_GENRE ""
+#define DEFAULT_MOUNT ""
+#define DEFAULT_URL ""
+#define DEFAULT_PROTOCOL SHOUT2SEND_PROTOCOL_HTTP
+
+static GstElementClass *parent_class = NULL;
+
+#ifdef SHOUT_FORMAT_WEBM
+#define WEBM_CAPS "; video/webm"
+#else
+#define WEBM_CAPS ""
+#endif
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/ogg; "
+ "audio/mpeg, mpegversion = (int) 1, layer = (int) [ 1, 3 ]" WEBM_CAPS));
+
+static void gst_shout2send_class_init (GstShout2sendClass * klass);
+static void gst_shout2send_base_init (GstShout2sendClass * klass);
+static void gst_shout2send_init (GstShout2send * shout2send);
+static void gst_shout2send_finalize (GstShout2send * shout2send);
+
+static gboolean gst_shout2send_event (GstBaseSink * sink, GstEvent * event);
+static gboolean gst_shout2send_unlock (GstBaseSink * basesink);
+static gboolean gst_shout2send_unlock_stop (GstBaseSink * basesink);
+static GstFlowReturn gst_shout2send_render (GstBaseSink * sink,
+ GstBuffer * buffer);
+static gboolean gst_shout2send_start (GstBaseSink * basesink);
+static gboolean gst_shout2send_stop (GstBaseSink * basesink);
+
+static void gst_shout2send_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_shout2send_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static gboolean gst_shout2send_setcaps (GstPad * pad, GstCaps * caps);
+
+static guint gst_shout2send_signals[LAST_SIGNAL] = { 0 };
+
+#define GST_TYPE_SHOUT_PROTOCOL (gst_shout2send_protocol_get_type())
+static GType
+gst_shout2send_protocol_get_type (void)
+{
+ static GType shout2send_protocol_type = 0;
+ static const GEnumValue shout2send_protocol[] = {
+ {SHOUT2SEND_PROTOCOL_XAUDIOCAST,
+ "Xaudiocast Protocol (icecast 1.3.x)", "xaudiocast"},
+ {SHOUT2SEND_PROTOCOL_ICY, "Icy Protocol (ShoutCast)", "icy"},
+ {SHOUT2SEND_PROTOCOL_HTTP, "Http Protocol (icecast 2.x)", "http"},
+ {0, NULL, NULL},
+ };
+
+ if (!shout2send_protocol_type) {
+ shout2send_protocol_type =
+ g_enum_register_static ("GstShout2SendProtocol", shout2send_protocol);
+ }
+
+
+ return shout2send_protocol_type;
+}
+
+GType
+gst_shout2send_get_type (void)
+{
+ static GType shout2send_type = 0;
+
+ if (!shout2send_type) {
+ static const GTypeInfo shout2send_info = {
+ sizeof (GstShout2sendClass),
+ (GBaseInitFunc) gst_shout2send_base_init,
+ NULL,
+ (GClassInitFunc) gst_shout2send_class_init,
+ NULL,
+ NULL,
+ sizeof (GstShout2send),
+ 0,
+ (GInstanceInitFunc) gst_shout2send_init,
+ };
+
+ static const GInterfaceInfo tag_setter_info = {
+ NULL,
+ NULL,
+ NULL
+ };
+
+ shout2send_type =
+ g_type_register_static (GST_TYPE_BASE_SINK, "GstShout2send",
+ &shout2send_info, 0);
+
+ g_type_add_interface_static (shout2send_type, GST_TYPE_TAG_SETTER,
+ &tag_setter_info);
+
+ }
+ return shout2send_type;
+}
+
+static void
+gst_shout2send_base_init (GstShout2sendClass * klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_static_pad_template (element_class, &sink_template);
+ gst_element_class_set_details_simple (element_class, "Icecast network sink",
+ "Sink/Network", "Sends data to an icecast server",
+ "Wim Taymans <wim.taymans@chello.be>, "
+ "Pedro Corte-Real <typo@netcabo.pt>, "
+ "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
+
+ GST_DEBUG_CATEGORY_INIT (shout2_debug, "shout2", 0, "shout2send element");
+}
+
+static void
+gst_shout2send_class_init (GstShout2sendClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstBaseSinkClass *gstbasesink_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstbasesink_class = (GstBaseSinkClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->set_property = gst_shout2send_set_property;
+ gobject_class->get_property = gst_shout2send_get_property;
+ gobject_class->finalize = (GObjectFinalizeFunc) gst_shout2send_finalize;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_IP,
+ g_param_spec_string ("ip", "ip", "ip", DEFAULT_IP,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PORT,
+ g_param_spec_int ("port", "port", "port", 1, G_MAXUSHORT, DEFAULT_PORT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PASSWORD,
+ g_param_spec_string ("password", "password", "password", DEFAULT_PASSWORD,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_USERNAME,
+ g_param_spec_string ("username", "username", "username", DEFAULT_USERNAME,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /* metadata */
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PUBLIC,
+ g_param_spec_boolean ("public", "public",
+ "If the stream should be listed on the server's stream directory",
+ DEFAULT_PUBLIC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STREAMNAME,
+ g_param_spec_string ("streamname", "streamname", "name of the stream",
+ DEFAULT_STREAMNAME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DESCRIPTION,
+ g_param_spec_string ("description", "description", "description",
+ DEFAULT_DESCRIPTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GENRE,
+ g_param_spec_string ("genre", "genre", "genre", DEFAULT_GENRE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PROTOCOL,
+ g_param_spec_enum ("protocol", "protocol", "Connection Protocol to use",
+ GST_TYPE_SHOUT_PROTOCOL, DEFAULT_PROTOCOL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+
+ /* icecast only */
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MOUNT,
+ g_param_spec_string ("mount", "mount", "mount", DEFAULT_MOUNT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_URL,
+ g_param_spec_string ("url", "url", "url", DEFAULT_URL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /* signals */
+ gst_shout2send_signals[SIGNAL_CONNECTION_PROBLEM] =
+ g_signal_new ("connection-problem", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_CLEANUP, G_STRUCT_OFFSET (GstShout2sendClass,
+ connection_problem), NULL, NULL, g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+
+ gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_shout2send_start);
+ gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_shout2send_stop);
+ gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_shout2send_unlock);
+ gstbasesink_class->unlock_stop =
+ GST_DEBUG_FUNCPTR (gst_shout2send_unlock_stop);
+ gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_shout2send_render);
+ gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_shout2send_event);
+}
+
+static void
+gst_shout2send_init (GstShout2send * shout2send)
+{
+ gst_base_sink_set_sync (GST_BASE_SINK (shout2send), FALSE);
+
+ gst_pad_set_setcaps_function (GST_BASE_SINK_PAD (shout2send),
+ GST_DEBUG_FUNCPTR (gst_shout2send_setcaps));
+
+ shout2send->timer = gst_poll_new_timer ();
+
+ shout2send->ip = g_strdup (DEFAULT_IP);
+ shout2send->port = DEFAULT_PORT;
+ shout2send->password = g_strdup (DEFAULT_PASSWORD);
+ shout2send->username = g_strdup (DEFAULT_USERNAME);
+ shout2send->streamname = g_strdup (DEFAULT_STREAMNAME);
+ shout2send->description = g_strdup (DEFAULT_DESCRIPTION);
+ shout2send->genre = g_strdup (DEFAULT_GENRE);
+ shout2send->mount = g_strdup (DEFAULT_MOUNT);
+ shout2send->url = g_strdup (DEFAULT_URL);
+ shout2send->protocol = DEFAULT_PROTOCOL;
+ shout2send->ispublic = DEFAULT_PUBLIC;
+
+ shout2send->tags = gst_tag_list_new ();
+ shout2send->conn = NULL;
+ shout2send->audio_format = SHOUT_FORMAT_VORBIS;
+ shout2send->connected = FALSE;
+ shout2send->songmetadata = NULL;
+ shout2send->songartist = NULL;
+ shout2send->songtitle = NULL;
+}
+
+static void
+gst_shout2send_finalize (GstShout2send * shout2send)
+{
+ g_free (shout2send->ip);
+ g_free (shout2send->password);
+ g_free (shout2send->username);
+ g_free (shout2send->streamname);
+ g_free (shout2send->description);
+ g_free (shout2send->genre);
+ g_free (shout2send->mount);
+ g_free (shout2send->url);
+
+ gst_tag_list_free (shout2send->tags);
+
+ gst_poll_free (shout2send->timer);
+
+ G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (shout2send));
+}
+
+static void
+set_shout_metadata (const GstTagList * list, const gchar * tag,
+ gpointer user_data)
+{
+ GstShout2send *shout2send = (GstShout2send *) user_data;
+ char **shout_metadata = &(shout2send->songmetadata);
+ char **song_artist = &(shout2send->songartist);
+ char **song_title = &(shout2send->songtitle);
+
+ gchar *value;
+
+ GST_DEBUG ("tag: %s being added", tag);
+ if (strcmp (tag, GST_TAG_ARTIST) == 0) {
+ if (gst_tag_get_type (tag) == G_TYPE_STRING) {
+ if (!gst_tag_list_get_string (list, tag, &value)) {
+ GST_DEBUG ("Error reading \"%s\" tag value", tag);
+ return;
+ }
+
+ if (*song_artist != NULL)
+ g_free (*song_artist);
+
+ *song_artist = g_strdup (value);
+ }
+ } else if (strcmp (tag, GST_TAG_TITLE) == 0) {
+ if (gst_tag_get_type (tag) == G_TYPE_STRING) {
+ if (!gst_tag_list_get_string (list, tag, &value)) {
+ GST_DEBUG ("Error reading \"%s\" tag value", tag);
+ return;
+ }
+
+ if (*song_title != NULL)
+ g_free (*song_title);
+
+ *song_title = g_strdup (value);
+ }
+ }
+
+ if (*shout_metadata != NULL)
+ g_free (*shout_metadata);
+
+
+ if (*song_title && *song_artist) {
+ *shout_metadata = g_strdup_printf ("%s - %s", *song_artist, *song_title);
+ } else if (*song_title && *song_artist == NULL) {
+ *shout_metadata = g_strdup_printf ("Unknown - %s", *song_title);
+ } else if (*song_title == NULL && *song_artist) {
+ *shout_metadata = g_strdup_printf ("%s - Unknown", *song_artist);
+ } else {
+ *shout_metadata = g_strdup_printf ("Unknown - Unknown");
+ }
+
+ GST_LOG ("shout metadata is now: %s", *shout_metadata);
+}
+
+#if 0
+static void
+gst_shout2send_set_metadata (GstShout2send * shout2send)
+{
+ const GstTagList *user_tags;
+ GstTagList *copy;
+ char *tempmetadata;
+ shout_metadata_t *pmetadata;
+
+ g_return_if_fail (shout2send != NULL);
+ user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (shout2send));
+ if ((shout2send->tags == NULL) && (user_tags == NULL)) {
+ return;
+ }
+ copy = gst_tag_list_merge (user_tags, shout2send->tags,
+ gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (shout2send)));
+ /* lets get the artist and song tags */
+ tempmetadata = NULL;
+ gst_tag_list_foreach ((GstTagList *) copy, set_shout_metadata,
+ (gpointer) & tempmetadata);
+ if (tempmetadata) {
+ pmetadata = shout_metadata_new ();
+ shout_metadata_add (pmetadata, "song", tempmetadata);
+ shout_set_metadata (shout2send->conn, pmetadata);
+ shout_metadata_free (pmetadata);
+ }
+
+ gst_tag_list_free (copy);
+}
+#endif
+
+
+static gboolean
+gst_shout2send_event (GstBaseSink * sink, GstEvent * event)
+{
+ GstShout2send *shout2send;
+ gboolean ret = TRUE;
+
+ shout2send = GST_SHOUT2SEND (sink);
+
+ GST_LOG_OBJECT (shout2send, "got %s event", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_TAG:{
+ /* vorbis audio doesnt need metadata setting on the icecast level, only mp3 */
+ if (shout2send->tags && shout2send->audio_format == SHOUT_FORMAT_MP3) {
+ GstTagList *list;
+
+ gst_event_parse_tag (event, &list);
+ GST_DEBUG_OBJECT (shout2send, "tags=%" GST_PTR_FORMAT, list);
+ gst_tag_list_insert (shout2send->tags,
+ list,
+ gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (shout2send)));
+ /* lets get the artist and song tags */
+ gst_tag_list_foreach ((GstTagList *) list,
+ set_shout_metadata, shout2send);
+ if (shout2send->songmetadata && shout2send->connected) {
+ shout_metadata_t *pmetadata;
+
+ GST_DEBUG_OBJECT (shout2send, "metadata now: %s",
+ shout2send->songmetadata);
+
+ pmetadata = shout_metadata_new ();
+ shout_metadata_add (pmetadata, "song", shout2send->songmetadata);
+ shout_set_metadata (shout2send->conn, pmetadata);
+ shout_metadata_free (pmetadata);
+ }
+ }
+ break;
+ }
+ default:{
+ GST_LOG_OBJECT (shout2send, "let base class handle event");
+ if (GST_BASE_SINK_CLASS (parent_class)->event) {
+ event = gst_event_ref (event);
+ ret = GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
+ }
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_shout2send_start (GstBaseSink * basesink)
+{
+ GstShout2send *sink = GST_SHOUT2SEND (basesink);
+ const gchar *cur_prop;
+ gshort proto = 3;
+ gchar *version_string;
+
+ GST_DEBUG_OBJECT (sink, "starting");
+
+ sink->conn = shout_new ();
+
+ switch (sink->protocol) {
+ case SHOUT2SEND_PROTOCOL_XAUDIOCAST:
+ proto = SHOUT_PROTOCOL_XAUDIOCAST;
+ break;
+ case SHOUT2SEND_PROTOCOL_ICY:
+ proto = SHOUT_PROTOCOL_ICY;
+ break;
+ case SHOUT2SEND_PROTOCOL_HTTP:
+ proto = SHOUT_PROTOCOL_HTTP;
+ break;
+ }
+
+ cur_prop = "protocol";
+ GST_DEBUG_OBJECT (sink, "setting protocol: %d", sink->protocol);
+ if (shout_set_protocol (sink->conn, proto) != SHOUTERR_SUCCESS)
+ goto set_failed;
+
+ /* --- FIXME: shout requires an ip, and fails if it is given a host. */
+ /* may want to put convert_to_ip(shout2send->ip) here */
+ cur_prop = "ip";
+ GST_DEBUG_OBJECT (sink, "setting ip: %s", sink->ip);
+ if (shout_set_host (sink->conn, sink->ip) != SHOUTERR_SUCCESS)
+ goto set_failed;
+
+ cur_prop = "port";
+ GST_DEBUG_OBJECT (sink, "setting port: %u", sink->port);
+ if (shout_set_port (sink->conn, sink->port) != SHOUTERR_SUCCESS)
+ goto set_failed;
+
+ cur_prop = "password";
+ GST_DEBUG_OBJECT (sink, "setting password: %s", sink->password);
+ if (shout_set_password (sink->conn, sink->password) != SHOUTERR_SUCCESS)
+ goto set_failed;
+
+ cur_prop = "public";
+ GST_DEBUG_OBJECT (sink, "setting %s: %u", cur_prop, sink->ispublic);
+ if (shout_set_public (sink->conn,
+ (sink->ispublic ? 1 : 0)) != SHOUTERR_SUCCESS)
+ goto set_failed;
+
+ cur_prop = "streamname";
+ GST_DEBUG_OBJECT (sink, "setting %s: %s", cur_prop, sink->streamname);
+ if (shout_set_name (sink->conn, sink->streamname) != SHOUTERR_SUCCESS)
+ goto set_failed;
+
+ cur_prop = "description";
+ GST_DEBUG_OBJECT (sink, "setting %s: %s", cur_prop, sink->description);
+ if (shout_set_description (sink->conn, sink->description) != SHOUTERR_SUCCESS)
+ goto set_failed;
+
+ cur_prop = "genre";
+ GST_DEBUG_OBJECT (sink, "setting %s: %s", cur_prop, sink->genre);
+ if (shout_set_genre (sink->conn, sink->genre) != SHOUTERR_SUCCESS)
+ goto set_failed;
+
+ cur_prop = "mount";
+ GST_DEBUG_OBJECT (sink, "setting %s: %s", cur_prop, sink->mount);
+ if (shout_set_mount (sink->conn, sink->mount) != SHOUTERR_SUCCESS)
+ goto set_failed;
+
+ cur_prop = "username";
+ GST_DEBUG_OBJECT (sink, "setting %s: %s", cur_prop, "source");
+ if (shout_set_user (sink->conn, sink->username) != SHOUTERR_SUCCESS)
+ goto set_failed;
+
+ version_string = gst_version_string ();
+ cur_prop = "agent";
+ GST_DEBUG_OBJECT (sink, "setting %s: %s", cur_prop, version_string);
+ if (shout_set_agent (sink->conn, version_string) != SHOUTERR_SUCCESS) {
+ g_free (version_string);
+ goto set_failed;
+ }
+
+ g_free (version_string);
+ return TRUE;
+
+/* ERROR */
+set_failed:
+ {
+ GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL),
+ ("Error setting %s: %s", cur_prop, shout_get_error (sink->conn)));
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_shout2send_connect (GstShout2send * sink)
+{
+ const char *format =
+ (sink->audio_format == SHOUT_FORMAT_VORBIS) ? "vorbis" :
+ ((sink->audio_format == SHOUT_FORMAT_MP3) ? "mp3" : "unknown");
+#ifdef SHOUT_FORMAT_WEBM
+ if (sink->audio_format == SHOUT_FORMAT_WEBM)
+ format = "webm";
+#endif
+ GST_DEBUG_OBJECT (sink, "Connection format is: %s", format);
+
+ if (shout_set_format (sink->conn, sink->audio_format) != SHOUTERR_SUCCESS)
+ goto could_not_set_format;
+
+ if (shout_open (sink->conn) != SHOUTERR_SUCCESS)
+ goto could_not_connect;
+
+ GST_DEBUG_OBJECT (sink, "connected to server");
+ sink->connected = TRUE;
+
+ /* let's set metadata */
+ if (sink->songmetadata) {
+ shout_metadata_t *pmetadata;
+
+ GST_DEBUG_OBJECT (sink, "shout metadata now: %s", sink->songmetadata);
+ pmetadata = shout_metadata_new ();
+ shout_metadata_add (pmetadata, "song", sink->songmetadata);
+ shout_set_metadata (sink->conn, pmetadata);
+ shout_metadata_free (pmetadata);
+ }
+
+ return TRUE;
+
+/* ERRORS */
+could_not_set_format:
+ {
+ GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL),
+ ("Error setting connection format: %s", shout_get_error (sink->conn)));
+ return FALSE;
+ }
+
+could_not_connect:
+ {
+ GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
+ (_("Could not connect to server")),
+ ("shout_open() failed: err=%s", shout_get_error (sink->conn)));
+ g_signal_emit (sink, gst_shout2send_signals[SIGNAL_CONNECTION_PROBLEM], 0,
+ shout_get_errno (sink->conn));
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_shout2send_stop (GstBaseSink * basesink)
+{
+ GstShout2send *sink = GST_SHOUT2SEND (basesink);
+
+ if (sink->conn) {
+ if (sink->connected)
+ shout_close (sink->conn);
+ shout_free (sink->conn);
+ sink->conn = NULL;
+ }
+
+ if (sink->songmetadata) {
+ g_free (sink->songmetadata);
+ sink->songmetadata = NULL;
+ }
+
+ sink->connected = FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+gst_shout2send_unlock (GstBaseSink * basesink)
+{
+ GstShout2send *sink;
+
+ sink = GST_SHOUT2SEND (basesink);
+
+ GST_DEBUG_OBJECT (basesink, "unlock");
+ gst_poll_set_flushing (sink->timer, TRUE);
+
+ return TRUE;
+}
+
+static gboolean
+gst_shout2send_unlock_stop (GstBaseSink * basesink)
+{
+ GstShout2send *sink;
+
+ sink = GST_SHOUT2SEND (basesink);
+
+ GST_DEBUG_OBJECT (basesink, "unlock_stop");
+ gst_poll_set_flushing (sink->timer, FALSE);
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_shout2send_render (GstBaseSink * basesink, GstBuffer * buf)
+{
+ GstShout2send *sink;
+ glong ret;
+ gint delay;
+ GstFlowReturn fret;
+
+ sink = GST_SHOUT2SEND (basesink);
+
+ /* presumably we connect here because we need to know the format before
+ * we can set up the connection, which we don't know yet in _start() */
+ if (!sink->connected) {
+ if (!gst_shout2send_connect (sink))
+ return GST_FLOW_ERROR;
+ }
+
+ delay = shout_delay (sink->conn);
+
+ if (delay > 0) {
+ GST_LOG_OBJECT (sink, "waiting %d msec", delay);
+ if (gst_poll_wait (sink->timer, GST_MSECOND * delay) == -1) {
+ GST_LOG_OBJECT (sink, "unlocked");
+
+ fret = gst_base_sink_wait_preroll (basesink);
+ if (fret != GST_FLOW_OK)
+ return fret;
+ }
+ } else {
+ GST_LOG_OBJECT (sink, "we're %d msec late", -delay);
+ }
+
+ GST_LOG_OBJECT (sink, "sending %u bytes of data", GST_BUFFER_SIZE (buf));
+ ret = shout_send (sink->conn, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+ if (ret != SHOUTERR_SUCCESS)
+ goto send_error;
+
+ return GST_FLOW_OK;
+
+/* ERRORS */
+send_error:
+ {
+ GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL),
+ ("shout_send() failed: %s", shout_get_error (sink->conn)));
+ g_signal_emit (sink, gst_shout2send_signals[SIGNAL_CONNECTION_PROBLEM], 0,
+ shout_get_errno (sink->conn));
+ return GST_FLOW_ERROR;
+ }
+}
+
+static void
+gst_shout2send_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstShout2send *shout2send;
+
+ shout2send = GST_SHOUT2SEND (object);
+ switch (prop_id) {
+
+ case ARG_IP:
+ if (shout2send->ip)
+ g_free (shout2send->ip);
+ shout2send->ip = g_strdup (g_value_get_string (value));
+ break;
+ case ARG_PORT:
+ shout2send->port = g_value_get_int (value);
+ break;
+ case ARG_PASSWORD:
+ if (shout2send->password)
+ g_free (shout2send->password);
+ shout2send->password = g_strdup (g_value_get_string (value));
+ break;
+ case ARG_USERNAME:
+ if (shout2send->username)
+ g_free (shout2send->username);
+ shout2send->username = g_strdup (g_value_get_string (value));
+ break;
+ case ARG_PUBLIC:
+ shout2send->ispublic = g_value_get_boolean (value);
+ break;
+ case ARG_STREAMNAME: /* Name of the stream */
+ if (shout2send->streamname)
+ g_free (shout2send->streamname);
+ shout2send->streamname = g_strdup (g_value_get_string (value));
+ break;
+ case ARG_DESCRIPTION: /* Description of the stream */
+ if (shout2send->description)
+ g_free (shout2send->description);
+ shout2send->description = g_strdup (g_value_get_string (value));
+ break;
+ case ARG_GENRE: /* Genre of the stream */
+ if (shout2send->genre)
+ g_free (shout2send->genre);
+ shout2send->genre = g_strdup (g_value_get_string (value));
+ break;
+ case ARG_PROTOCOL: /* protocol to connect with */
+ shout2send->protocol = g_value_get_enum (value);
+ break;
+ case ARG_MOUNT: /* mountpoint of stream (icecast only) */
+ if (shout2send->mount)
+ g_free (shout2send->mount);
+ shout2send->mount = g_strdup (g_value_get_string (value));
+ break;
+ case ARG_URL: /* Url of the stream (I'm guessing) */
+ if (shout2send->url)
+ g_free (shout2send->url);
+ shout2send->url = g_strdup (g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_shout2send_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstShout2send *shout2send;
+
+ shout2send = GST_SHOUT2SEND (object);
+ switch (prop_id) {
+
+ case ARG_IP:
+ g_value_set_string (value, shout2send->ip);
+ break;
+ case ARG_PORT:
+ g_value_set_int (value, shout2send->port);
+ break;
+ case ARG_PASSWORD:
+ g_value_set_string (value, shout2send->password);
+ break;
+ case ARG_USERNAME:
+ g_value_set_string (value, shout2send->username);
+ break;
+ case ARG_PUBLIC:
+ g_value_set_boolean (value, shout2send->ispublic);
+ break;
+ case ARG_STREAMNAME: /* Name of the stream */
+ g_value_set_string (value, shout2send->streamname);
+ break;
+ case ARG_DESCRIPTION: /* Description of the stream */
+ g_value_set_string (value, shout2send->description);
+ break;
+ case ARG_GENRE: /* Genre of the stream */
+ g_value_set_string (value, shout2send->genre);
+ break;
+ case ARG_PROTOCOL: /* protocol to connect with */
+ g_value_set_enum (value, shout2send->protocol);
+ break;
+ case ARG_MOUNT: /* mountpoint of stream (icecast only) */
+ g_value_set_string (value, shout2send->mount);
+ break;
+ case ARG_URL: /* Url of stream (I'm guessing) */
+ g_value_set_string (value, shout2send->url);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+gst_shout2send_setcaps (GstPad * pad, GstCaps * caps)
+{
+ const gchar *mimetype;
+ GstShout2send *shout2send;
+ gboolean ret = TRUE;
+
+ shout2send = GST_SHOUT2SEND (GST_OBJECT_PARENT (pad));
+
+ mimetype = gst_structure_get_name (gst_caps_get_structure (caps, 0));
+
+ GST_DEBUG_OBJECT (shout2send, "mimetype of caps given is: %s", mimetype);
+
+ if (!strcmp (mimetype, "audio/mpeg")) {
+ shout2send->audio_format = SHOUT_FORMAT_MP3;
+ } else if (!strcmp (mimetype, "application/ogg")) {
+ shout2send->audio_format = SHOUT_FORMAT_VORBIS;
+#ifdef SHOUT_FORMAT_WEBM
+ } else if (!strcmp (mimetype, "video/webm")) {
+ shout2send->audio_format = SHOUT_FORMAT_WEBM;
+#endif
+ } else {
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+#ifdef ENABLE_NLS
+ setlocale (LC_ALL, "");
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+ return gst_element_register (plugin, "shout2send", GST_RANK_NONE,
+ GST_TYPE_SHOUT2SEND);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "shout2send",
+ "Sends data to an icecast server using libshout2",
+ plugin_init,
+ VERSION, "LGPL", "libshout2", "http://www.icecast.org/download.html")
diff --git a/ext/shout2/gstshout2.h b/ext/shout2/gstshout2.h
new file mode 100644
index 0000000..1e3cd5b
--- /dev/null
+++ b/ext/shout2/gstshout2.h
@@ -0,0 +1,97 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_SHOUT2SEND_H__
+#define __GST_SHOUT2SEND_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+#include <shout/shout.h>
+
+G_BEGIN_DECLS
+
+ /* Protocol type enum */
+typedef enum {
+ SHOUT2SEND_PROTOCOL_XAUDIOCAST = 1,
+ SHOUT2SEND_PROTOCOL_ICY,
+ SHOUT2SEND_PROTOCOL_HTTP
+} GstShout2SendProtocol;
+
+
+/* Definition of structure storing data for this element. */
+typedef struct _GstShout2send GstShout2send;
+struct _GstShout2send {
+ GstBaseSink parent;
+
+ GstShout2SendProtocol protocol;
+
+ GstPoll *timer;
+
+ shout_t *conn;
+
+ gchar *ip;
+ guint port;
+ gchar *password;
+ gchar *username;
+ gchar *streamname;
+ gchar *description;
+ gchar *genre;
+ gchar *mount;
+ gchar *url;
+ gboolean connected;
+ gboolean ispublic;
+ gchar *songmetadata;
+ gchar *songartist;
+ gchar *songtitle;
+ guint16 audio_format;
+
+ GstTagList* tags;
+};
+
+
+
+/* Standard definition defining a class for this element. */
+typedef struct _GstShout2sendClass GstShout2sendClass;
+struct _GstShout2sendClass {
+ GstBaseSinkClass parent_class;
+
+ /* signal callbacks */
+ void (*connection_problem) (GstElement *element,guint errno);
+};
+
+/* Standard macros for defining types for this element. */
+#define GST_TYPE_SHOUT2SEND \
+ (gst_shout2send_get_type())
+#define GST_SHOUT2SEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SHOUT2SEND,GstShout2send))
+#define GST_SHOUT2SEND_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SHOUT2SEND,GstShout2sendClass))
+#define GST_IS_SHOUT2SEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SHOUT2SEND))
+#define GST_IS_SHOUT2SEND_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SHOUT2SEND))
+
+/* Standard function returning type information. */
+GType gst_shout2send_get_type(void);
+
+
+G_END_DECLS
+
+#endif /* __GST_SHOUT2SEND_H__ */
diff --git a/ext/soup/Makefile.am b/ext/soup/Makefile.am
new file mode 100644
index 0000000..6916b17
--- /dev/null
+++ b/ext/soup/Makefile.am
@@ -0,0 +1,10 @@
+plugin_LTLIBRARIES = libgstsouphttpsrc.la
+
+libgstsouphttpsrc_la_SOURCES = gstsouphttpsrc.c gstsouphttpclientsink.c gstsoup.c
+
+libgstsouphttpsrc_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(SOUP_CFLAGS)
+libgstsouphttpsrc_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-@GST_MAJORMINOR@ $(GST_BASE_LIBS) $(SOUP_LIBS)
+libgstsouphttpsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstsouphttpsrc_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstsouphttpsrc.h gstsouphttpclientsink.h
diff --git a/ext/soup/Makefile.in b/ext/soup/Makefile.in
new file mode 100644
index 0000000..bbb13ad
--- /dev/null
+++ b/ext/soup/Makefile.in
@@ -0,0 +1,824 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/soup
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstsouphttpsrc_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libgstsouphttpsrc_la_OBJECTS = \
+ libgstsouphttpsrc_la-gstsouphttpsrc.lo \
+ libgstsouphttpsrc_la-gstsouphttpclientsink.lo \
+ libgstsouphttpsrc_la-gstsoup.lo
+libgstsouphttpsrc_la_OBJECTS = $(am_libgstsouphttpsrc_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstsouphttpsrc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstsouphttpsrc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(libgstsouphttpsrc_la_CFLAGS) $(CFLAGS) \
+ $(libgstsouphttpsrc_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstsouphttpsrc_la_SOURCES)
+DIST_SOURCES = $(libgstsouphttpsrc_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstsouphttpsrc.la
+libgstsouphttpsrc_la_SOURCES = gstsouphttpsrc.c gstsouphttpclientsink.c gstsoup.c
+libgstsouphttpsrc_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(SOUP_CFLAGS)
+libgstsouphttpsrc_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-@GST_MAJORMINOR@ $(GST_BASE_LIBS) $(SOUP_LIBS)
+libgstsouphttpsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstsouphttpsrc_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = gstsouphttpsrc.h gstsouphttpclientsink.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/soup/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/soup/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstsouphttpsrc.la: $(libgstsouphttpsrc_la_OBJECTS) $(libgstsouphttpsrc_la_DEPENDENCIES) $(EXTRA_libgstsouphttpsrc_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstsouphttpsrc_la_LINK) -rpath $(plugindir) $(libgstsouphttpsrc_la_OBJECTS) $(libgstsouphttpsrc_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstsouphttpsrc_la-gstsoup.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstsouphttpsrc_la-gstsouphttpclientsink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstsouphttpsrc_la-gstsouphttpsrc.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstsouphttpsrc_la-gstsouphttpsrc.lo: gstsouphttpsrc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsouphttpsrc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsouphttpsrc_la_CFLAGS) $(CFLAGS) -MT libgstsouphttpsrc_la-gstsouphttpsrc.lo -MD -MP -MF $(DEPDIR)/libgstsouphttpsrc_la-gstsouphttpsrc.Tpo -c -o libgstsouphttpsrc_la-gstsouphttpsrc.lo `test -f 'gstsouphttpsrc.c' || echo '$(srcdir)/'`gstsouphttpsrc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstsouphttpsrc_la-gstsouphttpsrc.Tpo $(DEPDIR)/libgstsouphttpsrc_la-gstsouphttpsrc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsouphttpsrc.c' object='libgstsouphttpsrc_la-gstsouphttpsrc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsouphttpsrc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsouphttpsrc_la_CFLAGS) $(CFLAGS) -c -o libgstsouphttpsrc_la-gstsouphttpsrc.lo `test -f 'gstsouphttpsrc.c' || echo '$(srcdir)/'`gstsouphttpsrc.c
+
+libgstsouphttpsrc_la-gstsouphttpclientsink.lo: gstsouphttpclientsink.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsouphttpsrc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsouphttpsrc_la_CFLAGS) $(CFLAGS) -MT libgstsouphttpsrc_la-gstsouphttpclientsink.lo -MD -MP -MF $(DEPDIR)/libgstsouphttpsrc_la-gstsouphttpclientsink.Tpo -c -o libgstsouphttpsrc_la-gstsouphttpclientsink.lo `test -f 'gstsouphttpclientsink.c' || echo '$(srcdir)/'`gstsouphttpclientsink.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstsouphttpsrc_la-gstsouphttpclientsink.Tpo $(DEPDIR)/libgstsouphttpsrc_la-gstsouphttpclientsink.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsouphttpclientsink.c' object='libgstsouphttpsrc_la-gstsouphttpclientsink.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsouphttpsrc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsouphttpsrc_la_CFLAGS) $(CFLAGS) -c -o libgstsouphttpsrc_la-gstsouphttpclientsink.lo `test -f 'gstsouphttpclientsink.c' || echo '$(srcdir)/'`gstsouphttpclientsink.c
+
+libgstsouphttpsrc_la-gstsoup.lo: gstsoup.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsouphttpsrc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsouphttpsrc_la_CFLAGS) $(CFLAGS) -MT libgstsouphttpsrc_la-gstsoup.lo -MD -MP -MF $(DEPDIR)/libgstsouphttpsrc_la-gstsoup.Tpo -c -o libgstsouphttpsrc_la-gstsoup.lo `test -f 'gstsoup.c' || echo '$(srcdir)/'`gstsoup.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstsouphttpsrc_la-gstsoup.Tpo $(DEPDIR)/libgstsouphttpsrc_la-gstsoup.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsoup.c' object='libgstsouphttpsrc_la-gstsoup.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsouphttpsrc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsouphttpsrc_la_CFLAGS) $(CFLAGS) -c -o libgstsouphttpsrc_la-gstsoup.lo `test -f 'gstsoup.c' || echo '$(srcdir)/'`gstsoup.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/soup/gstsoup.c b/ext/soup/gstsoup.c
new file mode 100644
index 0000000..de71df8
--- /dev/null
+++ b/ext/soup/gstsoup.c
@@ -0,0 +1,47 @@
+/* GStreamer
+ * Copyright (C) 2007-2008 Wouter Cloetens <wouter@mind.be>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst-i18n-plugin.h>
+
+#include "gstsouphttpsrc.h"
+#include "gstsouphttpclientsink.h"
+
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+#ifdef ENABLE_NLS
+ GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+ LOCALEDIR);
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+ gst_element_register (plugin, "souphttpsrc", GST_RANK_PRIMARY,
+ GST_TYPE_SOUP_HTTP_SRC);
+ gst_element_register (plugin, "souphttpclientsink", GST_RANK_NONE,
+ GST_TYPE_SOUP_HTTP_CLIENT_SINK);
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "soup",
+ "libsoup HTTP client src/sink",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/soup/gstsouphttpclientsink.c b/ext/soup/gstsouphttpclientsink.c
new file mode 100644
index 0000000..dc9e941
--- /dev/null
+++ b/ext/soup/gstsouphttpclientsink.c
@@ -0,0 +1,765 @@
+/* GStreamer
+ * Copyright (C) 2011 David Schleef <ds@entropywave.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
+ * Boston, MA 02110-1335, USA.
+ */
+/**
+ * SECTION:element-gstsouphttpclientsink
+ *
+ * The souphttpclientsink element sends pipeline data to an HTTP server
+ * using HTTP PUT commands.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch -v videotestsrc num-buffers=300 ! theoraenc ! oggmux !
+ * souphttpclientsink location=http://server/filename.ogv
+ * ]|
+ *
+ * This example encodes 10 seconds of video and sends it to the HTTP
+ * server "server" using HTTP PUT commands.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+#include "gstsouphttpclientsink.h"
+
+#include <gst/glib-compat-private.h>
+
+GST_DEBUG_CATEGORY_STATIC (souphttpclientsink_dbg);
+#define GST_CAT_DEFAULT souphttpclientsink_dbg
+
+/* prototypes */
+
+
+static void gst_soup_http_client_sink_set_property (GObject * object,
+ guint property_id, const GValue * value, GParamSpec * pspec);
+static void gst_soup_http_client_sink_get_property (GObject * object,
+ guint property_id, GValue * value, GParamSpec * pspec);
+static void gst_soup_http_client_sink_dispose (GObject * object);
+static void gst_soup_http_client_sink_finalize (GObject * object);
+
+static gboolean gst_soup_http_client_sink_set_caps (GstBaseSink * sink,
+ GstCaps * caps);
+static void gst_soup_http_client_sink_get_times (GstBaseSink * sink,
+ GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
+static gboolean gst_soup_http_client_sink_start (GstBaseSink * sink);
+static gboolean gst_soup_http_client_sink_stop (GstBaseSink * sink);
+static gboolean gst_soup_http_client_sink_unlock (GstBaseSink * sink);
+static gboolean gst_soup_http_client_sink_event (GstBaseSink * sink,
+ GstEvent * event);
+static GstFlowReturn gst_soup_http_client_sink_preroll (GstBaseSink * sink,
+ GstBuffer * buffer);
+static GstFlowReturn gst_soup_http_client_sink_render (GstBaseSink * sink,
+ GstBuffer * buffer);
+
+static void free_buffer_list (GList * list);
+static void gst_soup_http_client_sink_reset (GstSoupHttpClientSink *
+ souphttpsink);
+static void authenticate (SoupSession * session, SoupMessage * msg,
+ SoupAuth * auth, gboolean retrying, gpointer user_data);
+static void callback (SoupSession * session, SoupMessage * msg,
+ gpointer user_data);
+static gboolean gst_soup_http_client_sink_set_proxy (GstSoupHttpClientSink *
+ souphttpsink, const gchar * uri);
+
+enum
+{
+ PROP_0,
+ PROP_LOCATION,
+ PROP_USER_AGENT,
+ PROP_AUTOMATIC_REDIRECT,
+ PROP_PROXY,
+ PROP_USER_ID,
+ PROP_USER_PW,
+ PROP_PROXY_ID,
+ PROP_PROXY_PW,
+ PROP_COOKIES,
+ PROP_SESSION
+};
+
+#define DEFAULT_USER_AGENT "GStreamer souphttpclientsink "
+
+/* pad templates */
+
+static GstStaticPadTemplate gst_soup_http_client_sink_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+
+/* class initialization */
+
+#define DEBUG_INIT(bla) \
+ GST_DEBUG_CATEGORY_INIT (souphttpclientsink_dbg, "souphttpclientsink", 0, \
+ "souphttpclientsink element");
+
+GST_BOILERPLATE_FULL (GstSoupHttpClientSink, gst_soup_http_client_sink,
+ GstBaseSink, GST_TYPE_BASE_SINK, DEBUG_INIT);
+
+static void
+gst_soup_http_client_sink_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_soup_http_client_sink_sink_template);
+
+ gst_element_class_set_details_simple (element_class, "HTTP client sink",
+ "Generic", "Sends streams to HTTP server via PUT",
+ "David Schleef <ds@entropywave.com>");
+}
+
+static void
+gst_soup_http_client_sink_class_init (GstSoupHttpClientSinkClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstBaseSinkClass *base_sink_class = GST_BASE_SINK_CLASS (klass);
+
+ gobject_class->set_property = gst_soup_http_client_sink_set_property;
+ gobject_class->get_property = gst_soup_http_client_sink_get_property;
+ gobject_class->dispose = gst_soup_http_client_sink_dispose;
+ gobject_class->finalize = gst_soup_http_client_sink_finalize;
+ base_sink_class->set_caps =
+ GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_set_caps);
+ if (0)
+ base_sink_class->get_times =
+ GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_get_times);
+ base_sink_class->start = GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_start);
+ base_sink_class->stop = GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_stop);
+ base_sink_class->unlock =
+ GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_unlock);
+ base_sink_class->event = GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_event);
+ if (0)
+ base_sink_class->preroll =
+ GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_preroll);
+ base_sink_class->render =
+ GST_DEBUG_FUNCPTR (gst_soup_http_client_sink_render);
+
+ g_object_class_install_property (gobject_class,
+ PROP_LOCATION,
+ g_param_spec_string ("location", "Location",
+ "URI to send to", "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_USER_AGENT,
+ g_param_spec_string ("user-agent", "User-Agent",
+ "Value of the User-Agent HTTP request header field",
+ DEFAULT_USER_AGENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_AUTOMATIC_REDIRECT,
+ g_param_spec_boolean ("automatic-redirect", "automatic-redirect",
+ "Automatically follow HTTP redirects (HTTP Status Code 3xx)",
+ TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_PROXY,
+ g_param_spec_string ("proxy", "Proxy",
+ "HTTP proxy server URI", "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_USER_ID,
+ g_param_spec_string ("user-id", "user-id",
+ "user id for authentication", "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_USER_PW,
+ g_param_spec_string ("user-pw", "user-pw",
+ "user password for authentication", "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_PROXY_ID,
+ g_param_spec_string ("proxy-id", "proxy-id",
+ "user id for proxy authentication", "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_PROXY_PW,
+ g_param_spec_string ("proxy-pw", "proxy-pw",
+ "user password for proxy authentication", "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_SESSION,
+ g_param_spec_object ("session", "session",
+ "SoupSession object to use for communication",
+ SOUP_TYPE_SESSION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_COOKIES,
+ g_param_spec_boxed ("cookies", "Cookies", "HTTP request cookies",
+ G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+}
+
+static void
+gst_soup_http_client_sink_init (GstSoupHttpClientSink * souphttpsink,
+ GstSoupHttpClientSinkClass * souphttpsink_class)
+{
+ const char *proxy;
+
+ souphttpsink->mutex = g_mutex_new ();
+ souphttpsink->cond = g_cond_new ();
+
+ souphttpsink->location = NULL;
+ souphttpsink->automatic_redirect = TRUE;
+ souphttpsink->user_agent = g_strdup (DEFAULT_USER_AGENT);
+ souphttpsink->user_id = NULL;
+ souphttpsink->user_pw = NULL;
+ souphttpsink->proxy_id = NULL;
+ souphttpsink->proxy_pw = NULL;
+ souphttpsink->prop_session = NULL;
+ souphttpsink->timeout = 1;
+ proxy = g_getenv ("http_proxy");
+ if (proxy && !gst_soup_http_client_sink_set_proxy (souphttpsink, proxy)) {
+ GST_WARNING_OBJECT (souphttpsink,
+ "The proxy in the http_proxy env var (\"%s\") cannot be parsed.",
+ proxy);
+ }
+
+ gst_soup_http_client_sink_reset (souphttpsink);
+}
+
+static void
+gst_soup_http_client_sink_reset (GstSoupHttpClientSink * souphttpsink)
+{
+ g_free (souphttpsink->reason_phrase);
+ souphttpsink->reason_phrase = NULL;
+ souphttpsink->status_code = 0;
+ souphttpsink->offset = 0;
+
+}
+
+static gboolean
+gst_soup_http_client_sink_set_proxy (GstSoupHttpClientSink * souphttpsink,
+ const gchar * uri)
+{
+ if (souphttpsink->proxy) {
+ soup_uri_free (souphttpsink->proxy);
+ souphttpsink->proxy = NULL;
+ }
+ if (g_str_has_prefix (uri, "http://")) {
+ souphttpsink->proxy = soup_uri_new (uri);
+ } else {
+ gchar *new_uri = g_strconcat ("http://", uri, NULL);
+
+ souphttpsink->proxy = soup_uri_new (new_uri);
+ g_free (new_uri);
+ }
+
+ return TRUE;
+}
+
+void
+gst_soup_http_client_sink_set_property (GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (object);
+
+ g_mutex_lock (souphttpsink->mutex);
+ switch (property_id) {
+ case PROP_SESSION:
+ if (souphttpsink->prop_session) {
+ g_object_unref (souphttpsink->prop_session);
+ }
+ souphttpsink->prop_session = g_value_dup_object (value);
+ break;
+ case PROP_LOCATION:
+ g_free (souphttpsink->location);
+ souphttpsink->location = g_value_dup_string (value);
+ souphttpsink->offset = 0;
+ break;
+ case PROP_USER_AGENT:
+ g_free (souphttpsink->user_agent);
+ souphttpsink->user_agent = g_value_dup_string (value);
+ break;
+ case PROP_AUTOMATIC_REDIRECT:
+ souphttpsink->automatic_redirect = g_value_get_boolean (value);
+ break;
+ case PROP_USER_ID:
+ g_free (souphttpsink->user_id);
+ souphttpsink->user_id = g_value_dup_string (value);
+ break;
+ case PROP_USER_PW:
+ g_free (souphttpsink->user_pw);
+ souphttpsink->user_pw = g_value_dup_string (value);
+ break;
+ case PROP_PROXY_ID:
+ g_free (souphttpsink->proxy_id);
+ souphttpsink->proxy_id = g_value_dup_string (value);
+ break;
+ case PROP_PROXY_PW:
+ g_free (souphttpsink->proxy_pw);
+ souphttpsink->proxy_pw = g_value_dup_string (value);
+ break;
+ case PROP_PROXY:
+ {
+ const gchar *proxy;
+
+ proxy = g_value_get_string (value);
+
+ if (proxy == NULL) {
+ GST_WARNING ("proxy property cannot be NULL");
+ goto done;
+ }
+ if (!gst_soup_http_client_sink_set_proxy (souphttpsink, proxy)) {
+ GST_WARNING ("badly formatted proxy URI");
+ goto done;
+ }
+ break;
+ }
+ case PROP_COOKIES:
+ g_strfreev (souphttpsink->cookies);
+ souphttpsink->cookies = g_strdupv (g_value_get_boxed (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+done:
+ g_mutex_unlock (souphttpsink->mutex);
+}
+
+void
+gst_soup_http_client_sink_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (object);
+
+ switch (property_id) {
+ case PROP_SESSION:
+ g_value_set_object (value, souphttpsink->prop_session);
+ break;
+ case PROP_LOCATION:
+ g_value_set_string (value, souphttpsink->location);
+ break;
+ case PROP_AUTOMATIC_REDIRECT:
+ g_value_set_boolean (value, souphttpsink->automatic_redirect);
+ break;
+ case PROP_USER_AGENT:
+ g_value_set_string (value, souphttpsink->user_agent);
+ break;
+ case PROP_USER_ID:
+ g_value_set_string (value, souphttpsink->user_id);
+ break;
+ case PROP_USER_PW:
+ g_value_set_string (value, souphttpsink->user_pw);
+ break;
+ case PROP_PROXY_ID:
+ g_value_set_string (value, souphttpsink->proxy_id);
+ break;
+ case PROP_PROXY_PW:
+ g_value_set_string (value, souphttpsink->proxy_pw);
+ break;
+ case PROP_PROXY:
+ if (souphttpsink->proxy == NULL)
+ g_value_set_static_string (value, "");
+ else {
+ char *proxy = soup_uri_to_string (souphttpsink->proxy, FALSE);
+
+ g_value_set_string (value, proxy);
+ g_free (proxy);
+ }
+ break;
+ case PROP_COOKIES:
+ g_value_set_boxed (value, g_strdupv (souphttpsink->cookies));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+void
+gst_soup_http_client_sink_dispose (GObject * object)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (object);
+
+ /* clean up as possible. may be called multiple times */
+ if (souphttpsink->prop_session)
+ g_object_unref (souphttpsink->prop_session);
+ souphttpsink->prop_session = NULL;
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+void
+gst_soup_http_client_sink_finalize (GObject * object)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (object);
+
+ /* clean up object here */
+
+ g_free (souphttpsink->user_agent);
+ g_free (souphttpsink->user_id);
+ g_free (souphttpsink->user_pw);
+ g_free (souphttpsink->proxy_id);
+ g_free (souphttpsink->proxy_pw);
+ if (souphttpsink->proxy)
+ soup_uri_free (souphttpsink->proxy);
+ g_free (souphttpsink->location);
+
+ g_cond_free (souphttpsink->cond);
+ g_mutex_free (souphttpsink->mutex);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+
+static gboolean
+gst_soup_http_client_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (sink);
+ GstStructure *structure;
+ const GValue *value_array;
+ int i, n;
+
+ structure = gst_caps_get_structure (caps, 0);
+ value_array = gst_structure_get_value (structure, "streamheader");
+ if (value_array) {
+ free_buffer_list (souphttpsink->streamheader_buffers);
+ souphttpsink->streamheader_buffers = NULL;
+
+ n = gst_value_array_get_size (value_array);
+ for (i = 0; i < n; i++) {
+ const GValue *value;
+ GstBuffer *buffer;
+ value = gst_value_array_get_value (value_array, i);
+ buffer = GST_BUFFER (gst_value_get_buffer (value));
+ souphttpsink->streamheader_buffers =
+ g_list_append (souphttpsink->streamheader_buffers,
+ gst_buffer_ref (buffer));
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+gst_soup_http_client_sink_get_times (GstBaseSink * sink, GstBuffer * buffer,
+ GstClockTime * start, GstClockTime * end)
+{
+
+}
+
+static gboolean
+thread_ready_idle_cb (gpointer data)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (data);
+
+ GST_LOG_OBJECT (souphttpsink, "thread ready");
+
+ g_mutex_lock (souphttpsink->mutex);
+ g_cond_signal (souphttpsink->cond);
+ g_mutex_unlock (souphttpsink->mutex);
+
+ return FALSE; /* only run once */
+}
+
+static gpointer
+thread_func (gpointer ptr)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (ptr);
+
+ GST_DEBUG ("thread start");
+
+ g_main_loop_run (souphttpsink->loop);
+
+ GST_DEBUG ("thread quit");
+
+ return NULL;
+}
+
+static gboolean
+gst_soup_http_client_sink_start (GstBaseSink * sink)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (sink);
+
+ if (souphttpsink->prop_session) {
+ souphttpsink->session = souphttpsink->prop_session;
+ } else {
+ GSource *source;
+ GError *error = NULL;
+
+ souphttpsink->context = g_main_context_new ();
+
+ /* set up idle source to signal when the main loop is running and
+ * it's safe for ::stop() to call g_main_loop_quit() */
+ source = g_idle_source_new ();
+ g_source_set_callback (source, thread_ready_idle_cb, sink, NULL);
+ g_source_attach (source, souphttpsink->context);
+ g_source_unref (source);
+
+ souphttpsink->loop = g_main_loop_new (souphttpsink->context, TRUE);
+
+ g_mutex_lock (souphttpsink->mutex);
+
+ /* FIXME: error handling */
+#if !GLIB_CHECK_VERSION (2, 31, 0)
+ souphttpsink->thread = g_thread_create (thread_func, souphttpsink,
+ TRUE, &error);
+#else
+ souphttpsink->thread = g_thread_try_new ("souphttpclientsink-thread",
+ thread_func, souphttpsink, &error);
+#endif
+
+ GST_LOG_OBJECT (souphttpsink, "waiting for main loop thread to start up");
+ g_cond_wait (souphttpsink->cond, souphttpsink->mutex);
+ g_mutex_unlock (souphttpsink->mutex);
+ GST_LOG_OBJECT (souphttpsink, "main loop thread running");
+
+ souphttpsink->session =
+ soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
+ souphttpsink->context, SOUP_SESSION_USER_AGENT,
+ souphttpsink->user_agent, SOUP_SESSION_TIMEOUT, souphttpsink->timeout,
+ NULL);
+
+ //soup_session_add_feature (souphttpsink->session,
+ // SOUP_SESSION_FEATURE (soup_logger_new (SOUP_LOGGER_LOG_BODY, 100)));
+
+ g_signal_connect (souphttpsink->session, "authenticate",
+ G_CALLBACK (authenticate), souphttpsink);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gst_soup_http_client_sink_stop (GstBaseSink * sink)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (sink);
+
+ GST_DEBUG ("stop");
+
+ if (souphttpsink->prop_session == NULL) {
+ soup_session_abort (souphttpsink->session);
+ g_object_unref (souphttpsink->session);
+ }
+
+ if (souphttpsink->loop) {
+ g_main_loop_quit (souphttpsink->loop);
+ g_thread_join (souphttpsink->thread);
+ g_main_loop_unref (souphttpsink->loop);
+ souphttpsink->loop = NULL;
+ }
+ if (souphttpsink->context) {
+ g_main_context_unref (souphttpsink->context);
+ souphttpsink->context = NULL;
+ }
+
+ gst_soup_http_client_sink_reset (souphttpsink);
+
+ return TRUE;
+}
+
+static gboolean
+gst_soup_http_client_sink_unlock (GstBaseSink * sink)
+{
+ GST_DEBUG ("unlock");
+
+ return TRUE;
+}
+
+static gboolean
+gst_soup_http_client_sink_event (GstBaseSink * sink, GstEvent * event)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (sink);
+
+ GST_DEBUG_OBJECT (souphttpsink, "event");
+
+ if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
+ GST_DEBUG_OBJECT (souphttpsink, "got eos");
+ g_mutex_lock (souphttpsink->mutex);
+ while (souphttpsink->message) {
+ GST_DEBUG_OBJECT (souphttpsink, "waiting");
+ g_cond_wait (souphttpsink->cond, souphttpsink->mutex);
+ }
+ g_mutex_unlock (souphttpsink->mutex);
+ GST_DEBUG_OBJECT (souphttpsink, "finished eos");
+ }
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_soup_http_client_sink_preroll (GstBaseSink * sink, GstBuffer * buffer)
+{
+ GST_DEBUG ("preroll");
+
+ return GST_FLOW_OK;
+}
+
+static void
+free_buffer_list (GList * list)
+{
+ GList *g;
+ for (g = list; g; g = g_list_next (g)) {
+ GstBuffer *buffer = g->data;
+ gst_buffer_unref (buffer);
+ }
+ g_list_free (list);
+}
+
+static void
+send_message_locked (GstSoupHttpClientSink * souphttpsink)
+{
+ GList *g;
+ guint64 n;
+
+ if (souphttpsink->queued_buffers == NULL || souphttpsink->message) {
+ return;
+ }
+
+ /* If the URI went away, drop all these buffers */
+ if (souphttpsink->location == NULL) {
+ free_buffer_list (souphttpsink->queued_buffers);
+ souphttpsink->queued_buffers = NULL;
+ return;
+ }
+
+ souphttpsink->message = soup_message_new ("PUT", souphttpsink->location);
+
+ n = 0;
+ if (souphttpsink->offset == 0) {
+ for (g = souphttpsink->streamheader_buffers; g; g = g_list_next (g)) {
+ GstBuffer *buffer = g->data;
+ soup_message_body_append (souphttpsink->message->request_body,
+ SOUP_MEMORY_STATIC, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer));
+ n += GST_BUFFER_SIZE (buffer);
+ }
+ }
+
+ for (g = souphttpsink->queued_buffers; g; g = g_list_next (g)) {
+ GstBuffer *buffer = g->data;
+ if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_IN_CAPS)) {
+ soup_message_body_append (souphttpsink->message->request_body,
+ SOUP_MEMORY_STATIC, GST_BUFFER_DATA (buffer),
+ GST_BUFFER_SIZE (buffer));
+ n += GST_BUFFER_SIZE (buffer);
+ }
+ }
+
+ if (souphttpsink->offset != 0) {
+ char *s;
+ s = g_strdup_printf ("bytes %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT "/*",
+ souphttpsink->offset, souphttpsink->offset + n - 1);
+ soup_message_headers_append (souphttpsink->message->request_headers,
+ "Content-Range", s);
+ g_free (s);
+ }
+
+ if (n == 0) {
+ free_buffer_list (souphttpsink->queued_buffers);
+ souphttpsink->queued_buffers = NULL;
+ g_object_unref (souphttpsink->message);
+ souphttpsink->message = NULL;
+ return;
+ }
+
+ souphttpsink->sent_buffers = souphttpsink->queued_buffers;
+ souphttpsink->queued_buffers = NULL;
+
+ GST_DEBUG_OBJECT (souphttpsink,
+ "queue message %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT,
+ souphttpsink->offset, n);
+ soup_session_queue_message (souphttpsink->session, souphttpsink->message,
+ callback, souphttpsink);
+
+ souphttpsink->offset += n;
+}
+
+static gboolean
+send_message (GstSoupHttpClientSink * souphttpsink)
+{
+ g_mutex_lock (souphttpsink->mutex);
+ send_message_locked (souphttpsink);
+ g_mutex_unlock (souphttpsink->mutex);
+
+ return FALSE;
+}
+
+static void
+callback (SoupSession * session, SoupMessage * msg, gpointer user_data)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (user_data);
+
+ GST_DEBUG_OBJECT (souphttpsink, "callback status=%d %s",
+ msg->status_code, msg->reason_phrase);
+
+ g_mutex_lock (souphttpsink->mutex);
+ g_cond_signal (souphttpsink->cond);
+ souphttpsink->message = NULL;
+
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+ souphttpsink->status_code = msg->status_code;
+ souphttpsink->reason_phrase = g_strdup (msg->reason_phrase);
+ g_mutex_unlock (souphttpsink->mutex);
+ return;
+ }
+
+ free_buffer_list (souphttpsink->sent_buffers);
+ souphttpsink->sent_buffers = NULL;
+
+ send_message_locked (souphttpsink);
+ g_mutex_unlock (souphttpsink->mutex);
+}
+
+static GstFlowReturn
+gst_soup_http_client_sink_render (GstBaseSink * sink, GstBuffer * buffer)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (sink);
+ GSource *source;
+ gboolean wake;
+
+ if (souphttpsink->status_code != 0) {
+ /* FIXME we should allow a moderate amount of retries. */
+ GST_ELEMENT_ERROR (souphttpsink, RESOURCE, WRITE,
+ ("Could not write to HTTP URI"),
+ ("error: %d %s", souphttpsink->status_code,
+ souphttpsink->reason_phrase));
+ return GST_FLOW_ERROR;
+ }
+
+ g_mutex_lock (souphttpsink->mutex);
+ if (souphttpsink->location != NULL) {
+ wake = (souphttpsink->queued_buffers == NULL);
+ souphttpsink->queued_buffers =
+ g_list_append (souphttpsink->queued_buffers, gst_buffer_ref (buffer));
+
+ if (wake) {
+ source = g_idle_source_new ();
+ g_source_set_callback (source, (GSourceFunc) (send_message),
+ souphttpsink, NULL);
+ g_source_attach (source, souphttpsink->context);
+ g_source_unref (source);
+ }
+ }
+ g_mutex_unlock (souphttpsink->mutex);
+
+ return GST_FLOW_OK;
+}
+
+static void
+authenticate (SoupSession * session, SoupMessage * msg,
+ SoupAuth * auth, gboolean retrying, gpointer user_data)
+{
+ GstSoupHttpClientSink *souphttpsink = GST_SOUP_HTTP_CLIENT_SINK (user_data);
+
+ if (!retrying) {
+ if (souphttpsink->user_id && souphttpsink->user_pw) {
+ soup_auth_authenticate (auth,
+ souphttpsink->user_id, souphttpsink->user_pw);
+ }
+ }
+}
diff --git a/ext/soup/gstsouphttpclientsink.h b/ext/soup/gstsouphttpclientsink.h
new file mode 100644
index 0000000..fab1430
--- /dev/null
+++ b/ext/soup/gstsouphttpclientsink.h
@@ -0,0 +1,81 @@
+/* GStreamer
+ * Copyright (C) 2011 David Schleef <ds@entropywave.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GST_SOUP_HTTP_CLIENT_SINK_H_
+#define _GST_SOUP_HTTP_CLIENT_SINK_H_
+
+#include <gst/base/gstbasesink.h>
+#include <libsoup/soup.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SOUP_HTTP_CLIENT_SINK (gst_soup_http_client_sink_get_type())
+#define GST_SOUP_HTTP_CLIENT_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SOUP_HTTP_CLIENT_SINK,GstSoupHttpClientSink))
+#define GST_SOUP_HTTP_CLIENT_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SOUP_HTTP_CLIENT_SINK,GstSoupHttpClientSinkClass))
+#define GST_IS_SOUP_HTTP_CLIENT_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SOUP_HTTP_CLIENT_SINK))
+#define GST_IS_SOUP_HTTP_CLIENT_SINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SOUP_HTTP_CLIENT_SINK))
+
+typedef struct _GstSoupHttpClientSink GstSoupHttpClientSink;
+typedef struct _GstSoupHttpClientSinkClass GstSoupHttpClientSinkClass;
+
+struct _GstSoupHttpClientSink
+{
+ GstBaseSink base_souphttpsink;
+
+ GMutex *mutex;
+ GCond *cond;
+ GMainContext *context;
+ GMainLoop *loop;
+ GThread *thread;
+ SoupMessage *message;
+ SoupSession *session;
+ GList *queued_buffers;
+ GList *sent_buffers;
+ GList *streamheader_buffers;
+
+ int status_code;
+ char *reason_phrase;
+
+ guint64 offset;
+ int timeout;
+
+ /* properties */
+ SoupSession *prop_session;
+ char *location;
+ char *user_id;
+ char *user_pw;
+ SoupURI *proxy;
+ char *proxy_id;
+ char *proxy_pw;
+ char *user_agent;
+ gboolean automatic_redirect;
+ gchar **cookies;
+
+};
+
+struct _GstSoupHttpClientSinkClass
+{
+ GstBaseSinkClass base_souphttpsink_class;
+};
+
+GType gst_soup_http_client_sink_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ext/soup/gstsouphttpsrc.c b/ext/soup/gstsouphttpsrc.c
new file mode 100644
index 0000000..a31746d
--- /dev/null
+++ b/ext/soup/gstsouphttpsrc.c
@@ -0,0 +1,1676 @@
+/* GStreamer
+ * Copyright (C) 2007-2008 Wouter Cloetens <wouter@mind.be>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more
+ */
+
+/**
+ * SECTION:element-souphttpsrc
+ *
+ * This plugin reads data from a remote location specified by a URI.
+ * Supported protocols are 'http', 'https'.
+ *
+ * An HTTP proxy must be specified by its URL.
+ * If the "http_proxy" environment variable is set, its value is used.
+ * If built with libsoup's GNOME integration features, the GNOME proxy
+ * configuration will be used, or failing that, proxy autodetection.
+ * The #GstSoupHTTPSrc:proxy property can be used to override the default.
+ *
+ * In case the #GstSoupHTTPSrc:iradio-mode property is set and the location is
+ * an HTTP resource, souphttpsrc will send special Icecast HTTP headers to the
+ * server to request additional Icecast meta-information.
+ * If the server is not an Icecast server, it will behave as if the
+ * #GstSoupHTTPSrc:iradio-mode property were not set. If it is, souphttpsrc will
+ * output data with a media type of application/x-icy, in which case you will
+ * need to use the #ICYDemux element as follow-up element to extract the Icecast
+ * metadata and to determine the underlying media type.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch -v souphttpsrc location=https://some.server.org/index.html
+ * ! filesink location=/home/joe/server.html
+ * ]| The above pipeline reads a web page from a server using the HTTPS protocol
+ * and writes it to a local file.
+ * |[
+ * gst-launch -v souphttpsrc user-agent="FooPlayer 0.99 beta"
+ * automatic-redirect=false proxy=http://proxy.intranet.local:8080
+ * location=http://music.foobar.com/demo.mp3 ! mad ! audioconvert
+ * ! audioresample ! alsasink
+ * ]| The above pipeline will read and decode and play an mp3 file from a
+ * web server using the HTTP protocol. If the server sends redirects,
+ * the request fails instead of following the redirect. The specified
+ * HTTP proxy server is used. The User-Agent HTTP request header
+ * is set to a custom string instead of "GStreamer souphttpsrc."
+ * |[
+ * gst-launch -v souphttpsrc location=http://10.11.12.13/mjpeg
+ * do-timestamp=true ! multipartdemux
+ * ! image/jpeg,width=640,height=480 ! matroskamux
+ * ! filesink location=mjpeg.mkv
+ * ]| The above pipeline reads a motion JPEG stream from an IP camera
+ * using the HTTP protocol, encoded as mime/multipart image/jpeg
+ * parts, and writes a Matroska motion JPEG file. The width and
+ * height properties are set in the caps to provide the Matroska
+ * multiplexer with the information to set this in the header.
+ * Timestamps are set on the buffers as they arrive from the camera.
+ * These are used by the mime/multipart demultiplexer to emit timestamps
+ * on the JPEG-encoded video frame buffers. This allows the Matroska
+ * multiplexer to timestamp the frames in the resulting file.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* atoi() */
+#endif
+#include <gst/gstelement.h>
+#include <gst/gst-i18n-plugin.h>
+#ifdef HAVE_LIBSOUP_GNOME
+#include <libsoup/soup-gnome.h>
+#else
+#include <libsoup/soup.h>
+#endif
+#include "gstsouphttpsrc.h"
+
+#include <gst/tag/tag.h>
+
+#define SEEK_CHANGES
+GST_DEBUG_CATEGORY_STATIC (souphttpsrc_debug);
+#define GST_CAT_DEFAULT souphttpsrc_debug
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+enum
+{
+ PROP_0,
+ PROP_LOCATION,
+ PROP_IS_LIVE,
+ PROP_USER_AGENT,
+ PROP_AUTOMATIC_REDIRECT,
+ PROP_PROXY,
+ PROP_USER_ID,
+ PROP_USER_PW,
+ PROP_PROXY_ID,
+ PROP_PROXY_PW,
+ PROP_COOKIES,
+ PROP_IRADIO_MODE,
+ PROP_IRADIO_NAME,
+ PROP_IRADIO_GENRE,
+ PROP_IRADIO_URL,
+ PROP_IRADIO_TITLE,
+ PROP_TIMEOUT,
+#ifdef SEEK_CHANGES
+ PROP_EXTRA_HEADERS,
+ PROP_BLOCKSIZE,
+#else
+ PROP_EXTRA_HEADERS
+#endif
+};
+
+#define DEFAULT_USER_AGENT "GStreamer souphttpsrc "
+
+static void gst_soup_http_src_uri_handler_init (gpointer g_iface,
+ gpointer iface_data);
+static void gst_soup_http_src_finalize (GObject * gobject);
+
+static void gst_soup_http_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_soup_http_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_soup_http_src_create (GstPushSrc * psrc,
+ GstBuffer ** outbuf);
+static gboolean gst_soup_http_src_start (GstBaseSrc * bsrc);
+static gboolean gst_soup_http_src_stop (GstBaseSrc * bsrc);
+static gboolean gst_soup_http_src_get_size (GstBaseSrc * bsrc, guint64 * size);
+static gboolean gst_soup_http_src_is_seekable (GstBaseSrc * bsrc);
+static gboolean gst_soup_http_src_do_seek (GstBaseSrc * bsrc,
+ GstSegment * segment);
+static gboolean gst_soup_http_src_query (GstBaseSrc * bsrc, GstQuery * query);
+static gboolean gst_soup_http_src_unlock (GstBaseSrc * bsrc);
+static gboolean gst_soup_http_src_unlock_stop (GstBaseSrc * bsrc);
+static gboolean gst_soup_http_src_set_location (GstSoupHTTPSrc * src,
+ const gchar * uri);
+static gboolean gst_soup_http_src_set_proxy (GstSoupHTTPSrc * src,
+ const gchar * uri);
+static char *gst_soup_http_src_unicodify (const char *str);
+static gboolean gst_soup_http_src_build_message (GstSoupHTTPSrc * src);
+static void gst_soup_http_src_cancel_message (GstSoupHTTPSrc * src);
+static void gst_soup_http_src_queue_message (GstSoupHTTPSrc * src);
+static gboolean gst_soup_http_src_add_range_header (GstSoupHTTPSrc * src,
+ guint64 offset);
+static void gst_soup_http_src_session_unpause_message (GstSoupHTTPSrc * src);
+static void gst_soup_http_src_session_pause_message (GstSoupHTTPSrc * src);
+static void gst_soup_http_src_session_close (GstSoupHTTPSrc * src);
+static void gst_soup_http_src_parse_status (SoupMessage * msg,
+ GstSoupHTTPSrc * src);
+static void gst_soup_http_src_chunk_free (gpointer gstbuf);
+static SoupBuffer *gst_soup_http_src_chunk_allocator (SoupMessage * msg,
+ gsize max_len, gpointer user_data);
+static void gst_soup_http_src_got_chunk_cb (SoupMessage * msg,
+ SoupBuffer * chunk, GstSoupHTTPSrc * src);
+static void gst_soup_http_src_response_cb (SoupSession * session,
+ SoupMessage * msg, GstSoupHTTPSrc * src);
+static void gst_soup_http_src_got_headers_cb (SoupMessage * msg,
+ GstSoupHTTPSrc * src);
+static void gst_soup_http_src_got_body_cb (SoupMessage * msg,
+ GstSoupHTTPSrc * src);
+static void gst_soup_http_src_finished_cb (SoupMessage * msg,
+ GstSoupHTTPSrc * src);
+static void gst_soup_http_src_authenticate_cb (SoupSession * session,
+ SoupMessage * msg, SoupAuth * auth, gboolean retrying,
+ GstSoupHTTPSrc * src);
+
+static void
+_do_init (GType type)
+{
+ static const GInterfaceInfo urihandler_info = {
+ gst_soup_http_src_uri_handler_init,
+ NULL,
+ NULL
+ };
+
+ g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
+
+ GST_DEBUG_CATEGORY_INIT (souphttpsrc_debug, "souphttpsrc", 0,
+ "SOUP HTTP src");
+}
+
+GST_BOILERPLATE_FULL (GstSoupHTTPSrc, gst_soup_http_src, GstPushSrc,
+ GST_TYPE_PUSH_SRC, _do_init);
+
+static void
+gst_soup_http_src_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class, &srctemplate);
+
+ gst_element_class_set_details_simple (element_class, "HTTP client source",
+ "Source/Network",
+ "Receive data as a client over the network via HTTP using SOUP",
+ "Wouter Cloetens <wouter@mind.be>");
+}
+
+static void
+gst_soup_http_src_class_init (GstSoupHTTPSrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstBaseSrcClass *gstbasesrc_class;
+ GstPushSrcClass *gstpushsrc_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstbasesrc_class = (GstBaseSrcClass *) klass;
+ gstpushsrc_class = (GstPushSrcClass *) klass;
+
+ gobject_class->set_property = gst_soup_http_src_set_property;
+ gobject_class->get_property = gst_soup_http_src_get_property;
+ gobject_class->finalize = gst_soup_http_src_finalize;
+
+ g_object_class_install_property (gobject_class,
+ PROP_LOCATION,
+ g_param_spec_string ("location", "Location",
+ "Location to read from", "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_USER_AGENT,
+ g_param_spec_string ("user-agent", "User-Agent",
+ "Value of the User-Agent HTTP request header field",
+ DEFAULT_USER_AGENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_AUTOMATIC_REDIRECT,
+ g_param_spec_boolean ("automatic-redirect", "automatic-redirect",
+ "Automatically follow HTTP redirects (HTTP Status Code 3xx)",
+ TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_PROXY,
+ g_param_spec_string ("proxy", "Proxy",
+ "HTTP proxy server URI", "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_USER_ID,
+ g_param_spec_string ("user-id", "user-id",
+ "HTTP location URI user id for authentication", "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_USER_PW,
+ g_param_spec_string ("user-pw", "user-pw",
+ "HTTP location URI user password for authentication", "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_PROXY_ID,
+ g_param_spec_string ("proxy-id", "proxy-id",
+ "HTTP proxy URI user id for authentication", "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_PROXY_PW,
+ g_param_spec_string ("proxy-pw", "proxy-pw",
+ "HTTP proxy URI user password for authentication", "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_COOKIES,
+ g_param_spec_boxed ("cookies", "Cookies", "HTTP request cookies",
+ G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_IS_LIVE,
+ g_param_spec_boolean ("is-live", "is-live", "Act like a live source",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_TIMEOUT,
+ g_param_spec_uint ("timeout", "timeout",
+ "Value in seconds to timeout a blocking I/O (0 = No timeout).", 0,
+ 3600, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_EXTRA_HEADERS,
+ g_param_spec_boxed ("extra-headers", "Extra Headers",
+ "Extra headers to append to the HTTP request",
+ GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+#ifdef SEEK_CHANGES
+ g_object_class_install_property (gobject_class, PROP_BLOCKSIZE,
+ g_param_spec_int64 ("blocksize", "blocksize",
+ "Size of each buffer downloaded from libsoup",
+ -1, G_MAXUINT, 4096, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
+ /* icecast stuff */
+ g_object_class_install_property (gobject_class,
+ PROP_IRADIO_MODE,
+ g_param_spec_boolean ("iradio-mode",
+ "iradio-mode",
+ "Enable internet radio mode (extraction of shoutcast/icecast metadata)",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_IRADIO_NAME,
+ g_param_spec_string ("iradio-name",
+ "iradio-name", "Name of the stream", NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_IRADIO_GENRE,
+ g_param_spec_string ("iradio-genre",
+ "iradio-genre", "Genre of the stream", NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_IRADIO_URL,
+ g_param_spec_string ("iradio-url",
+ "iradio-url",
+ "Homepage URL for radio stream", NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class,
+ PROP_IRADIO_TITLE,
+ g_param_spec_string ("iradio-title",
+ "iradio-title",
+ "Name of currently playing song", NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_soup_http_src_start);
+ gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_soup_http_src_stop);
+ gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_soup_http_src_unlock);
+ gstbasesrc_class->unlock_stop =
+ GST_DEBUG_FUNCPTR (gst_soup_http_src_unlock_stop);
+ gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_soup_http_src_get_size);
+ gstbasesrc_class->is_seekable =
+ GST_DEBUG_FUNCPTR (gst_soup_http_src_is_seekable);
+ gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_soup_http_src_do_seek);
+ gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_soup_http_src_query);
+
+ gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_soup_http_src_create);
+}
+
+static void
+gst_soup_http_src_reset (GstSoupHTTPSrc * src)
+{
+ src->interrupted = FALSE;
+ src->retry = FALSE;
+ src->have_size = FALSE;
+ src->seekable = FALSE;
+ src->read_position = 0;
+ src->request_position = 0;
+ src->content_size = 0;
+
+#ifdef SEEK_CHANGES
+ src->file_size = 0;
+#endif
+ gst_caps_replace (&src->src_caps, NULL);
+ g_free (src->iradio_name);
+ src->iradio_name = NULL;
+ g_free (src->iradio_genre);
+ src->iradio_genre = NULL;
+ g_free (src->iradio_url);
+ src->iradio_url = NULL;
+ g_free (src->iradio_title);
+ src->iradio_title = NULL;
+}
+
+static void
+gst_soup_http_src_init (GstSoupHTTPSrc * src, GstSoupHTTPSrcClass * g_class)
+{
+ const gchar *proxy;
+
+ src->location = NULL;
+ src->automatic_redirect = TRUE;
+ src->user_agent = g_strdup (DEFAULT_USER_AGENT);
+ src->user_id = NULL;
+ src->user_pw = NULL;
+ src->proxy_id = NULL;
+ src->proxy_pw = NULL;
+ src->cookies = NULL;
+ src->iradio_mode = FALSE;
+ src->loop = NULL;
+ src->context = NULL;
+ src->session = NULL;
+ src->msg = NULL;
+#ifdef SEEK_CHANGES
+ src->file_size = 0;
+ src->range_size = 0;
+#endif
+ proxy = g_getenv ("http_proxy");
+ if (proxy && !gst_soup_http_src_set_proxy (src, proxy)) {
+ GST_WARNING_OBJECT (src,
+ "The proxy in the http_proxy env var (\"%s\") cannot be parsed.",
+ proxy);
+ }
+
+ gst_soup_http_src_reset (src);
+}
+
+static void
+gst_soup_http_src_finalize (GObject * gobject)
+{
+ GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (gobject);
+
+ GST_DEBUG_OBJECT (src, "finalize");
+
+ g_free (src->location);
+ g_free (src->user_agent);
+ if (src->proxy != NULL) {
+ soup_uri_free (src->proxy);
+ }
+ g_free (src->user_id);
+ g_free (src->user_pw);
+ g_free (src->proxy_id);
+ g_free (src->proxy_pw);
+ g_strfreev (src->cookies);
+
+ G_OBJECT_CLASS (parent_class)->finalize (gobject);
+}
+
+static void
+gst_soup_http_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (object);
+
+ switch (prop_id) {
+ case PROP_LOCATION:
+ {
+ const gchar *location;
+
+ location = g_value_get_string (value);
+
+ if (location == NULL) {
+ GST_WARNING ("location property cannot be NULL");
+ goto done;
+ }
+ if (!gst_soup_http_src_set_location (src, location)) {
+ GST_WARNING ("badly formatted location");
+ goto done;
+ }
+ break;
+ }
+ case PROP_USER_AGENT:
+ if (src->user_agent)
+ g_free (src->user_agent);
+ src->user_agent = g_value_dup_string (value);
+ break;
+ case PROP_IRADIO_MODE:
+ src->iradio_mode = g_value_get_boolean (value);
+ break;
+ case PROP_AUTOMATIC_REDIRECT:
+ src->automatic_redirect = g_value_get_boolean (value);
+ break;
+ case PROP_PROXY:
+ {
+ const gchar *proxy;
+
+ proxy = g_value_get_string (value);
+
+ if (proxy == NULL) {
+ GST_WARNING ("proxy property cannot be NULL");
+ goto done;
+ }
+ if (!gst_soup_http_src_set_proxy (src, proxy)) {
+ GST_WARNING ("badly formatted proxy URI");
+ goto done;
+ }
+ break;
+ }
+ case PROP_COOKIES:
+ {
+#ifdef GST_EXT_SOUP_MODIFICATION
+ char **array;
+#endif
+ g_strfreev (src->cookies);
+ src->cookies = g_strdupv (g_value_get_boxed (value));
+#ifdef GST_EXT_SOUP_MODIFICATION
+ if ((array = src->cookies) != NULL) {
+ while (*array != NULL) {
+ soup_cookie_jar_add_cookie (src->cookie_jar,
+ soup_cookie_parse (*array++, NULL));
+ }
+ }
+#endif
+ break;
+ }
+ case PROP_IS_LIVE:
+ gst_base_src_set_live (GST_BASE_SRC (src), g_value_get_boolean (value));
+ break;
+ case PROP_USER_ID:
+ if (src->user_id)
+ g_free (src->user_id);
+ src->user_id = g_value_dup_string (value);
+ break;
+ case PROP_USER_PW:
+ if (src->user_pw)
+ g_free (src->user_pw);
+ src->user_pw = g_value_dup_string (value);
+ break;
+ case PROP_PROXY_ID:
+ if (src->proxy_id)
+ g_free (src->proxy_id);
+ src->proxy_id = g_value_dup_string (value);
+ break;
+ case PROP_PROXY_PW:
+ if (src->proxy_pw)
+ g_free (src->proxy_pw);
+ src->proxy_pw = g_value_dup_string (value);
+ break;
+ case PROP_TIMEOUT:
+ src->timeout = g_value_get_uint (value);
+ break;
+ case PROP_EXTRA_HEADERS:{
+ const GstStructure *s = gst_value_get_structure (value);
+
+ if (src->extra_headers)
+ gst_structure_free (src->extra_headers);
+
+ src->extra_headers = s ? gst_structure_copy (s) : NULL;
+ break;
+ }
+#ifdef SEEK_CHANGES
+ case PROP_BLOCKSIZE:{
+ src->range_size = g_value_get_int64 (value);
+ break;
+ }
+#endif
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+done:
+ return;
+}
+
+static void
+gst_soup_http_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (object);
+
+ switch (prop_id) {
+ case PROP_LOCATION:
+ g_value_set_string (value, src->location);
+ break;
+ case PROP_USER_AGENT:
+ g_value_set_string (value, src->user_agent);
+ break;
+ case PROP_AUTOMATIC_REDIRECT:
+ g_value_set_boolean (value, src->automatic_redirect);
+ break;
+ case PROP_PROXY:
+ if (src->proxy == NULL)
+ g_value_set_static_string (value, "");
+ else {
+ char *proxy = soup_uri_to_string (src->proxy, FALSE);
+
+ g_value_set_string (value, proxy);
+ g_free (proxy);
+ }
+ break;
+ case PROP_COOKIES:
+ {
+#ifdef GST_EXT_SOUP_MODIFICATION
+ GSList *cookie_list, *c;
+ gchar **cookies, **array;
+
+ cookies = NULL;
+ if ((cookie_list = soup_cookie_jar_all_cookies (src->cookie_jar)) != NULL) {
+ cookies = g_new0 (gchar *, g_slist_length(cookie_list) + 1);
+ array = cookies;
+ for (c = cookie_list; c; c = c->next) {
+ *array++ = soup_cookie_to_set_cookie_header ((SoupCookie *)(c->data));
+ }
+ soup_cookies_free (cookie_list);
+ }
+ g_value_set_boxed (value, cookies);
+#else
+ g_value_set_boxed (value, g_strdupv (src->cookies));
+#endif
+ break;
+ }
+ case PROP_IS_LIVE:
+ g_value_set_boolean (value, gst_base_src_is_live (GST_BASE_SRC (src)));
+ break;
+ case PROP_IRADIO_MODE:
+ g_value_set_boolean (value, src->iradio_mode);
+ break;
+ case PROP_IRADIO_NAME:
+ g_value_set_string (value, src->iradio_name);
+ break;
+ case PROP_IRADIO_GENRE:
+ g_value_set_string (value, src->iradio_genre);
+ break;
+ case PROP_IRADIO_URL:
+ g_value_set_string (value, src->iradio_url);
+ break;
+ case PROP_IRADIO_TITLE:
+ g_value_set_string (value, src->iradio_title);
+ break;
+ case PROP_USER_ID:
+ g_value_set_string (value, src->user_id);
+ break;
+ case PROP_USER_PW:
+ g_value_set_string (value, src->user_pw);
+ break;
+ case PROP_PROXY_ID:
+ g_value_set_string (value, src->proxy_id);
+ break;
+ case PROP_PROXY_PW:
+ g_value_set_string (value, src->proxy_pw);
+ break;
+ case PROP_TIMEOUT:
+ g_value_set_uint (value, src->timeout);
+ break;
+ case PROP_EXTRA_HEADERS:
+ gst_value_set_structure (value, src->extra_headers);
+ break;
+#ifdef SEEK_CHANGES
+ case PROP_BLOCKSIZE:
+ g_value_set_int64 (value, src->range_size);
+ break;
+#endif
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gchar *
+gst_soup_http_src_unicodify (const gchar * str)
+{
+ const gchar *env_vars[] = { "GST_ICY_TAG_ENCODING",
+ "GST_TAG_ENCODING", NULL
+ };
+
+ return gst_tag_freeform_string_to_utf8 (str, -1, env_vars);
+}
+
+static void
+gst_soup_http_src_cancel_message (GstSoupHTTPSrc * src)
+{
+ if (src->msg != NULL) {
+ src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_CANCELLED;
+ soup_session_cancel_message (src->session, src->msg, SOUP_STATUS_CANCELLED);
+ }
+ src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE;
+ src->msg = NULL;
+}
+
+static void
+gst_soup_http_src_queue_message (GstSoupHTTPSrc * src)
+{
+ soup_session_queue_message (src->session, src->msg,
+ (SoupSessionCallback) gst_soup_http_src_response_cb, src);
+ src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_QUEUED;
+}
+
+static gboolean
+gst_soup_http_src_add_range_header (GstSoupHTTPSrc * src, guint64 offset)
+{
+ gchar buf[64];
+
+ gint rc;
+
+ soup_message_headers_remove (src->msg->request_headers, "Range");
+
+#ifdef GST_EXT_SOUP_MODIFICATION
+ /* Note : Some http server could not handle Range header in the middle of playing.
+ * Need to add Range header at first for seeking properly.
+ */
+ rc = g_snprintf (buf, sizeof (buf), "bytes=%" G_GUINT64_FORMAT "-", offset);
+ if (rc > sizeof (buf) || rc < 0)
+ return FALSE;
+ soup_message_headers_append (src->msg->request_headers, "Range", buf);
+#else
+ if (offset) {
+ rc = g_snprintf (buf, sizeof (buf), "bytes=%" G_GUINT64_FORMAT "-", offset);
+ if (rc > sizeof (buf) || rc < 0)
+ return FALSE;
+ soup_message_headers_append (src->msg->request_headers, "Range", buf);
+ }
+#endif
+ src->read_position = offset;
+ return TRUE;
+}
+
+static gboolean
+_append_extra_header (GQuark field_id, const GValue * value, gpointer user_data)
+{
+ GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (user_data);
+ const gchar *field_name = g_quark_to_string (field_id);
+ gchar *field_content = NULL;
+
+ if (G_VALUE_TYPE (value) == G_TYPE_STRING) {
+ field_content = g_value_dup_string (value);
+ } else {
+ GValue dest = { 0, };
+
+ g_value_init (&dest, G_TYPE_STRING);
+ if (g_value_transform (value, &dest)) {
+ field_content = g_value_dup_string (&dest);
+ }
+ }
+
+ if (field_content == NULL) {
+ GST_ERROR_OBJECT (src, "extra-headers field '%s' contains no value "
+ "or can't be converted to a string", field_name);
+ return FALSE;
+ }
+
+ GST_DEBUG_OBJECT (src, "Appending extra header: \"%s: %s\"", field_name,
+ field_content);
+ soup_message_headers_append (src->msg->request_headers, field_name,
+ field_content);
+
+ g_free (field_content);
+
+ return TRUE;
+}
+
+static gboolean
+_append_extra_headers (GQuark field_id, const GValue * value,
+ gpointer user_data)
+{
+ if (G_VALUE_TYPE (value) == GST_TYPE_ARRAY) {
+ guint n = gst_value_array_get_size (value);
+ guint i;
+
+ for (i = 0; i < n; i++) {
+ const GValue *v = gst_value_array_get_value (value, i);
+
+ if (!_append_extra_header (field_id, v, user_data))
+ return FALSE;
+ }
+ } else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
+ guint n = gst_value_list_get_size (value);
+ guint i;
+
+ for (i = 0; i < n; i++) {
+ const GValue *v = gst_value_list_get_value (value, i);
+
+ if (!_append_extra_header (field_id, v, user_data))
+ return FALSE;
+ }
+ } else {
+ return _append_extra_header (field_id, value, user_data);
+ }
+
+ return TRUE;
+}
+
+
+static gboolean
+gst_soup_http_src_add_extra_headers (GstSoupHTTPSrc * src)
+{
+ if (!src->extra_headers)
+ return TRUE;
+
+ return gst_structure_foreach (src->extra_headers, _append_extra_headers, src);
+}
+
+
+static void
+gst_soup_http_src_session_unpause_message (GstSoupHTTPSrc * src)
+{
+ soup_session_unpause_message (src->session, src->msg);
+}
+
+static void
+gst_soup_http_src_session_pause_message (GstSoupHTTPSrc * src)
+{
+ soup_session_pause_message (src->session, src->msg);
+}
+
+static void
+gst_soup_http_src_session_close (GstSoupHTTPSrc * src)
+{
+ if (src->session) {
+ soup_session_abort (src->session); /* This unrefs the message. */
+ g_object_unref (src->session);
+ src->session = NULL;
+ src->msg = NULL;
+ }
+}
+
+static void
+gst_soup_http_src_authenticate_cb (SoupSession * session, SoupMessage * msg,
+ SoupAuth * auth, gboolean retrying, GstSoupHTTPSrc * src)
+{
+ if (!retrying) {
+ /* First time authentication only, if we fail and are called again with retry true fall through */
+ if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
+ if (src->user_id && src->user_pw)
+ soup_auth_authenticate (auth, src->user_id, src->user_pw);
+ } else if (msg->status_code == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
+ if (src->proxy_id && src->proxy_pw)
+ soup_auth_authenticate (auth, src->proxy_id, src->proxy_pw);
+ }
+ }
+}
+
+static void
+gst_soup_http_src_headers_foreach (const gchar * name, const gchar * val,
+ gpointer src)
+{
+ GST_DEBUG_OBJECT (src, " %s: %s", name, val);
+}
+
+static void
+gst_soup_http_src_got_headers_cb (SoupMessage * msg, GstSoupHTTPSrc * src)
+{
+ const char *value;
+ GstTagList *tag_list;
+ GstBaseSrc *basesrc;
+ guint64 newsize;
+#ifdef SEEK_CHANGES
+ goffset start = 0, end = 0, total_length = 0;
+#endif
+ GHashTable *params = NULL;
+#ifdef GST_EXT_SOUP_MODIFICATION
+ gint idx = 0;
+ const char* blackTypes[] = {"application/xml", "text/html"};
+#endif
+
+ GST_DEBUG_OBJECT (src, "got headers:");
+ soup_message_headers_foreach (msg->response_headers,
+ gst_soup_http_src_headers_foreach, src);
+
+ if (msg->status_code == 407 && src->proxy_id && src->proxy_pw)
+ return;
+
+ if (src->automatic_redirect && SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
+#ifdef GST_EXT_SOUP_MODIFICATION
+ value = soup_message_headers_get (msg->response_headers, "Location");
+ gst_soup_http_src_set_location (src, value);
+ GST_DEBUG_OBJECT (src, "%u redirect to \"%s\"", msg->status_code, value);
+#else
+ GST_DEBUG_OBJECT (src, "%u redirect to \"%s\"", msg->status_code,
+ soup_message_headers_get (msg->response_headers, "Location"));
+#endif
+ return;
+ }
+
+ if (msg->status_code == SOUP_STATUS_UNAUTHORIZED)
+ return;
+
+ src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING;
+
+ /* Parse Content-Length. */
+ if (soup_message_headers_get_encoding (msg->response_headers) ==
+ SOUP_ENCODING_CONTENT_LENGTH) {
+ newsize = src->request_position +
+ soup_message_headers_get_content_length (msg->response_headers);
+ if (!src->have_size || (src->content_size != newsize)) {
+ src->content_size = newsize;
+#ifdef SEEK_CHANGES
+ if(!src->file_size)
+ src->file_size = newsize;
+#endif
+ src->have_size = TRUE;
+ src->seekable = TRUE;
+ GST_DEBUG_OBJECT (src, "size = %" G_GUINT64_FORMAT, src->content_size);
+
+ basesrc = GST_BASE_SRC_CAST (src);
+ gst_segment_set_duration (&basesrc->segment, GST_FORMAT_BYTES,
+ src->content_size);
+ gst_element_post_message (GST_ELEMENT (src),
+ gst_message_new_duration (GST_OBJECT (src), GST_FORMAT_BYTES,
+ src->content_size));
+ }
+#ifdef SEEK_CHANGES
+ soup_message_headers_get_content_range(msg->response_headers, &start, &end, &total_length);
+ if(total_length > 0)
+ {
+ src->file_size = total_length;
+ GST_DEBUG_OBJECT (src, "size = %" G_GUINT64_FORMAT, src->file_size);
+ basesrc = GST_BASE_SRC_CAST (src);
+ gst_segment_set_duration (&basesrc->segment, GST_FORMAT_BYTES,
+ src->file_size);
+ gst_element_post_message (GST_ELEMENT (src),
+ gst_message_new_duration (GST_OBJECT (src), GST_FORMAT_BYTES,
+ src->file_size));
+ }
+#endif
+ }
+
+ /* Icecast stuff */
+ tag_list = gst_tag_list_new ();
+
+ if ((value =
+ soup_message_headers_get (msg->response_headers,
+ "icy-metaint")) != NULL) {
+ gint icy_metaint = atoi (value);
+
+ GST_DEBUG_OBJECT (src, "icy-metaint: %s (parsed: %d)", value, icy_metaint);
+ if (icy_metaint > 0) {
+ if (src->src_caps)
+ gst_caps_unref (src->src_caps);
+
+ src->src_caps = gst_caps_new_simple ("application/x-icy",
+ "metadata-interval", G_TYPE_INT, icy_metaint, NULL);
+ }
+ }
+ if ((value =
+ soup_message_headers_get_content_type (msg->response_headers,
+ &params)) != NULL) {
+ GST_DEBUG_OBJECT (src, "Content-Type: %s", value);
+
+#ifdef GST_EXT_SOUP_MODIFICATION
+ for (idx = 0; idx < (sizeof(blackTypes) / sizeof(char *)); idx++) {
+ if (!g_ascii_strcasecmp(value, blackTypes[idx])) {
+ GST_DEBUG_OBJECT (src, "blackType: %s", blackTypes[idx]);
+ GST_ELEMENT_ERROR(src, STREAM, WRONG_TYPE, (0), (0));
+ src->ret = GST_FLOW_ERROR;
+ }
+ }
+#endif
+
+ if (g_ascii_strcasecmp (value, "audio/L16") == 0) {
+ gint channels = 2;
+ gint rate = 44100;
+ char *param;
+
+ if (src->src_caps)
+ gst_caps_unref (src->src_caps);
+
+ param = g_hash_table_lookup (params, "channels");
+ if (param != NULL)
+ channels = atol (param);
+
+ param = g_hash_table_lookup (params, "rate");
+ if (param != NULL)
+ rate = atol (param);
+
+ src->src_caps = gst_caps_new_simple ("audio/x-raw-int",
+ "channels", G_TYPE_INT, channels,
+ "rate", G_TYPE_INT, rate,
+ "width", G_TYPE_INT, 16,
+ "depth", G_TYPE_INT, 16,
+ "signed", G_TYPE_BOOLEAN, TRUE,
+ "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
+ } else {
+ /* Set the Content-Type field on the caps */
+ if (src->src_caps)
+ gst_caps_set_simple (src->src_caps, "content-type", G_TYPE_STRING,
+ value, NULL);
+ }
+ }
+
+ if (params != NULL)
+ g_hash_table_destroy (params);
+
+ if ((value =
+ soup_message_headers_get (msg->response_headers,
+ "icy-name")) != NULL) {
+ g_free (src->iradio_name);
+ src->iradio_name = gst_soup_http_src_unicodify (value);
+ if (src->iradio_name) {
+ g_object_notify (G_OBJECT (src), "iradio-name");
+ gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_ORGANIZATION,
+ src->iradio_name, NULL);
+ }
+ }
+ if ((value =
+ soup_message_headers_get (msg->response_headers,
+ "icy-genre")) != NULL) {
+ g_free (src->iradio_genre);
+ src->iradio_genre = gst_soup_http_src_unicodify (value);
+ if (src->iradio_genre) {
+ g_object_notify (G_OBJECT (src), "iradio-genre");
+ gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_GENRE,
+ src->iradio_genre, NULL);
+ }
+ }
+ if ((value = soup_message_headers_get (msg->response_headers, "icy-url"))
+ != NULL) {
+ g_free (src->iradio_url);
+ src->iradio_url = gst_soup_http_src_unicodify (value);
+ if (src->iradio_url) {
+ g_object_notify (G_OBJECT (src), "iradio-url");
+ gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_LOCATION,
+ src->iradio_url, NULL);
+ }
+ }
+ if (!gst_tag_list_is_empty (tag_list)) {
+ GST_DEBUG_OBJECT (src,
+ "calling gst_element_found_tags with %" GST_PTR_FORMAT, tag_list);
+ gst_element_found_tags (GST_ELEMENT_CAST (src), tag_list);
+ } else {
+ gst_tag_list_free (tag_list);
+ }
+
+ /* Handle HTTP errors. */
+ gst_soup_http_src_parse_status (msg, src);
+
+ /* Check if Range header was respected. */
+ if (src->ret == GST_FLOW_CUSTOM_ERROR &&
+ src->read_position && msg->status_code != SOUP_STATUS_PARTIAL_CONTENT) {
+ src->seekable = FALSE;
+ GST_ELEMENT_ERROR (src, RESOURCE, SEEK,
+ (_("Server does not support seeking.")),
+ ("Server does not accept Range HTTP header, URL: %s", src->location));
+ src->ret = GST_FLOW_ERROR;
+ }
+}
+
+/* Have body. Signal EOS. */
+static void
+gst_soup_http_src_got_body_cb (SoupMessage * msg, GstSoupHTTPSrc * src)
+{
+ if (G_UNLIKELY (msg != src->msg)) {
+ GST_DEBUG_OBJECT (src, "got body, but not for current message");
+ return;
+ }
+ if (G_UNLIKELY (src->session_io_status !=
+ GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING)) {
+ /* Probably a redirect. */
+ return;
+ }
+ GST_DEBUG_OBJECT (src, "got body");
+ src->ret = GST_FLOW_UNEXPECTED;
+ if (src->loop)
+ g_main_loop_quit (src->loop);
+ gst_soup_http_src_session_pause_message (src);
+}
+
+/* Finished. Signal EOS. */
+static void
+gst_soup_http_src_finished_cb (SoupMessage * msg, GstSoupHTTPSrc * src)
+{
+ if (G_UNLIKELY (msg != src->msg)) {
+ GST_DEBUG_OBJECT (src, "finished, but not for current message");
+ return;
+ }
+ GST_DEBUG_OBJECT (src, "finished");
+ src->ret = GST_FLOW_UNEXPECTED;
+ if (src->session_io_status == GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_CANCELLED) {
+ /* gst_soup_http_src_cancel_message() triggered this; probably a seek
+ * that occurred in the QUEUEING state; i.e. before the connection setup
+ * was complete. Do nothing */
+ } else if (src->session_io_status ==
+ GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING && src->read_position > 0) {
+ /* The server disconnected while streaming. Reconnect and seeking to the
+ * last location. */
+ src->retry = TRUE;
+ src->ret = GST_FLOW_CUSTOM_ERROR;
+ } else if (G_UNLIKELY (src->session_io_status !=
+ GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING)) {
+ /* FIXME: reason_phrase is not translated, add proper error message */
+ GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
+ ("%s", msg->reason_phrase),
+ ("libsoup status code %d", msg->status_code));
+ }
+ if (src->loop)
+ g_main_loop_quit (src->loop);
+}
+
+/* Buffer lifecycle management.
+ *
+ * gst_soup_http_src_create() runs the GMainLoop for this element, to let
+ * Soup take control.
+ * A GstBuffer is allocated in gst_soup_http_src_chunk_allocator() and
+ * associated with a SoupBuffer.
+ * Soup reads HTTP data in the GstBuffer's data buffer.
+ * The gst_soup_http_src_got_chunk_cb() is then called with the SoupBuffer.
+ * That sets gst_soup_http_src_create()'s return argument to the GstBuffer,
+ * increments its refcount (to 2), pauses the flow of data from the HTTP
+ * source to prevent gst_soup_http_src_got_chunk_cb() from being called
+ * again and breaks out of the GMainLoop.
+ * Because the SOUP_MESSAGE_OVERWRITE_CHUNKS flag is set, Soup frees the
+ * SoupBuffer and calls gst_soup_http_src_chunk_free(), which decrements the
+ * refcount (to 1).
+ * gst_soup_http_src_create() returns the GstBuffer. It will be freed by a
+ * downstream element.
+ * If Soup fails to read HTTP data, it does not call
+ * gst_soup_http_src_got_chunk_cb(), but still frees the SoupBuffer and
+ * calls gst_soup_http_src_chunk_free(), which decrements the GstBuffer's
+ * refcount to 0, freeing it.
+ */
+
+static void
+gst_soup_http_src_chunk_free (gpointer gstbuf)
+{
+ gst_buffer_unref (GST_BUFFER_CAST (gstbuf));
+}
+
+static SoupBuffer *
+gst_soup_http_src_chunk_allocator (SoupMessage * msg, gsize max_len,
+ gpointer user_data)
+{
+ GstSoupHTTPSrc *src = (GstSoupHTTPSrc *) user_data;
+ GstBaseSrc *basesrc = GST_BASE_SRC_CAST (src);
+ GstBuffer *gstbuf;
+ SoupBuffer *soupbuf;
+ gsize length;
+ GstFlowReturn rc;
+
+ if (max_len)
+ length = MIN (basesrc->blocksize, max_len);
+ else
+ length = basesrc->blocksize;
+ GST_DEBUG_OBJECT (src, "alloc %" G_GSIZE_FORMAT " bytes <= %" G_GSIZE_FORMAT,
+ length, max_len);
+
+
+ rc = gst_pad_alloc_buffer (GST_BASE_SRC_PAD (basesrc),
+ GST_BUFFER_OFFSET_NONE, length,
+ src->src_caps ? src->src_caps :
+ GST_PAD_CAPS (GST_BASE_SRC_PAD (basesrc)), &gstbuf);
+ if (G_UNLIKELY (rc != GST_FLOW_OK)) {
+ /* Failed to allocate buffer. Stall SoupSession and return error code
+ * to create(). */
+ src->ret = rc;
+ g_main_loop_quit (src->loop);
+ return NULL;
+ }
+
+ soupbuf = soup_buffer_new_with_owner (GST_BUFFER_DATA (gstbuf), length,
+ gstbuf, gst_soup_http_src_chunk_free);
+
+ return soupbuf;
+}
+
+static void
+gst_soup_http_src_got_chunk_cb (SoupMessage * msg, SoupBuffer * chunk,
+ GstSoupHTTPSrc * src)
+{
+ GstBaseSrc *basesrc;
+ guint64 new_position;
+
+ if (G_UNLIKELY (msg != src->msg)) {
+ GST_DEBUG_OBJECT (src, "got chunk, but not for current message");
+ return;
+ }
+ if (G_UNLIKELY (src->session_io_status !=
+ GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING)) {
+ /* Probably a redirect. */
+ return;
+ }
+ basesrc = GST_BASE_SRC_CAST (src);
+ GST_DEBUG_OBJECT (src, "got chunk of %" G_GSIZE_FORMAT " bytes",
+ chunk->length);
+
+ /* Extract the GstBuffer from the SoupBuffer and set its fields. */
+ *src->outbuf = GST_BUFFER_CAST (soup_buffer_get_owner (chunk));
+
+ GST_BUFFER_SIZE (*src->outbuf) = chunk->length;
+ GST_BUFFER_OFFSET (*src->outbuf) = basesrc->segment.last_stop;
+
+ gst_buffer_set_caps (*src->outbuf,
+ (src->src_caps) ? src->src_caps :
+ GST_PAD_CAPS (GST_BASE_SRC_PAD (basesrc)));
+
+ gst_buffer_ref (*src->outbuf);
+
+ new_position = src->read_position + chunk->length;
+ if (G_LIKELY (src->request_position == src->read_position))
+ src->request_position = new_position;
+ src->read_position = new_position;
+
+ src->ret = GST_FLOW_OK;
+ g_main_loop_quit (src->loop);
+ gst_soup_http_src_session_pause_message (src);
+}
+
+static void
+gst_soup_http_src_response_cb (SoupSession * session, SoupMessage * msg,
+ GstSoupHTTPSrc * src)
+{
+ if (G_UNLIKELY (msg != src->msg)) {
+ GST_DEBUG_OBJECT (src, "got response %d: %s, but not for current message",
+ msg->status_code, msg->reason_phrase);
+ return;
+ }
+ if (G_UNLIKELY (src->session_io_status !=
+ GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING)
+ && SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
+ /* Ignore redirections. */
+ return;
+ }
+ GST_DEBUG_OBJECT (src, "got response %d: %s", msg->status_code,
+ msg->reason_phrase);
+ if (src->session_io_status == GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING &&
+ src->read_position > 0) {
+ /* The server disconnected while streaming. Reconnect and seeking to the
+ * last location. */
+ src->retry = TRUE;
+ } else
+ gst_soup_http_src_parse_status (msg, src);
+ /* The session's SoupMessage object expires after this callback returns. */
+ src->msg = NULL;
+ g_main_loop_quit (src->loop);
+}
+
+#define SOUP_HTTP_SRC_ERROR(src,soup_msg,cat,code,error_message) \
+ GST_ELEMENT_ERROR ((src), cat, code, ("%s", error_message), \
+ ("%s (%d), URL: %s", (soup_msg)->reason_phrase, \
+ (soup_msg)->status_code, (src)->location));
+
+static void
+gst_soup_http_src_parse_status (SoupMessage * msg, GstSoupHTTPSrc * src)
+{
+ if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
+ switch (msg->status_code) {
+ case SOUP_STATUS_CANT_RESOLVE:
+ case SOUP_STATUS_CANT_RESOLVE_PROXY:
+ SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, NOT_FOUND,
+ _("Could not resolve server name."));
+ src->ret = GST_FLOW_ERROR;
+ break;
+ case SOUP_STATUS_CANT_CONNECT:
+ case SOUP_STATUS_CANT_CONNECT_PROXY:
+ SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, OPEN_READ,
+ _("Could not establish connection to server."));
+ src->ret = GST_FLOW_ERROR;
+ break;
+ case SOUP_STATUS_SSL_FAILED:
+ SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, OPEN_READ,
+ _("Secure connection setup failed."));
+ src->ret = GST_FLOW_ERROR;
+ break;
+ case SOUP_STATUS_IO_ERROR:
+ SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, READ,
+ _("A network error occured, or the server closed the connection "
+ "unexpectedly."));
+ src->ret = GST_FLOW_ERROR;
+ break;
+ case SOUP_STATUS_MALFORMED:
+ SOUP_HTTP_SRC_ERROR (src, msg, RESOURCE, READ,
+ _("Server sent bad data."));
+ src->ret = GST_FLOW_ERROR;
+ break;
+ case SOUP_STATUS_CANCELLED:
+ /* No error message when interrupted by program. */
+ break;
+ }
+ } else if (SOUP_STATUS_IS_CLIENT_ERROR (msg->status_code) ||
+ SOUP_STATUS_IS_REDIRECTION (msg->status_code) ||
+ SOUP_STATUS_IS_SERVER_ERROR (msg->status_code)) {
+ /* Report HTTP error. */
+ /* FIXME: reason_phrase is not translated and not suitable for user
+ * error dialog according to libsoup documentation.
+ * FIXME: error code (OPEN_READ vs. READ) should depend on http status? */
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+ ("%s", msg->reason_phrase),
+ ("%s (%d), URL: %s", msg->reason_phrase, msg->status_code,
+ src->location));
+ src->ret = GST_FLOW_ERROR;
+ }
+}
+
+static gboolean
+gst_soup_http_src_build_message (GstSoupHTTPSrc * src)
+{
+ src->msg = soup_message_new (SOUP_METHOD_GET, src->location);
+ if (!src->msg) {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+ ("Error parsing URL."), ("URL: %s", src->location));
+ return FALSE;
+ }
+ src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE;
+ soup_message_headers_append (src->msg->request_headers, "Connection",
+ "close");
+ if (src->iradio_mode) {
+ soup_message_headers_append (src->msg->request_headers, "icy-metadata",
+ "1");
+ }
+ if (src->cookies) {
+ gchar **cookie;
+#ifdef GST_EXT_SOUP_MODIFICATION
+ SoupURI *uri;
+ SoupCookie *cookie_parsed;
+ gchar *header;
+
+ uri = soup_uri_new (src->location);
+ for (cookie = src->cookies; *cookie != NULL; cookie++) {
+ if ((cookie_parsed = soup_cookie_parse (*cookie, uri)) != NULL) {
+ header = soup_cookie_to_cookie_header (cookie_parsed);
+ soup_message_headers_append (src->msg->request_headers, "Cookie",
+ header);
+ g_free (header);
+ soup_cookie_free (cookie_parsed);
+ }
+ }
+ soup_uri_free (uri);
+#else
+ for (cookie = src->cookies; *cookie != NULL; cookie++) {
+ soup_message_headers_append (src->msg->request_headers, "Cookie",
+ *cookie);
+ }
+#endif
+ }
+ soup_message_headers_append (src->msg->request_headers,
+ "transferMode.dlna.org", "Streaming");
+ src->retry = FALSE;
+
+ g_signal_connect (src->msg, "got_headers",
+ G_CALLBACK (gst_soup_http_src_got_headers_cb), src);
+ g_signal_connect (src->msg, "got_body",
+ G_CALLBACK (gst_soup_http_src_got_body_cb), src);
+ g_signal_connect (src->msg, "finished",
+ G_CALLBACK (gst_soup_http_src_finished_cb), src);
+ g_signal_connect (src->msg, "got_chunk",
+ G_CALLBACK (gst_soup_http_src_got_chunk_cb), src);
+ soup_message_set_flags (src->msg, SOUP_MESSAGE_OVERWRITE_CHUNKS |
+ (src->automatic_redirect ? 0 : SOUP_MESSAGE_NO_REDIRECT));
+ soup_message_set_chunk_allocator (src->msg,
+ gst_soup_http_src_chunk_allocator, src, NULL);
+#ifdef SEEK_CHANGES
+ //gst_soup_http_src_add_range_header (src, src->request_position);
+ if(src->range_size > 0)
+ soup_message_headers_set_range(src->msg->request_headers, src->request_position, (src->request_position+src->range_size-1));
+ else {
+ gst_soup_http_src_add_range_header (src, src->request_position);
+ gst_soup_http_src_add_extra_headers (src);
+ GST_DEBUG_OBJECT (src, "request headers:");
+ soup_message_headers_foreach (src->msg->request_headers,gst_soup_http_src_headers_foreach, src);
+ }
+#else
+ gst_soup_http_src_add_range_header (src, src->request_position);
+
+ gst_soup_http_src_add_extra_headers (src);
+
+ GST_DEBUG_OBJECT (src, "request headers:");
+ soup_message_headers_foreach (src->msg->request_headers,
+ gst_soup_http_src_headers_foreach, src);
+#endif
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_soup_http_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
+{
+ GstSoupHTTPSrc *src;
+
+ src = GST_SOUP_HTTP_SRC (psrc);
+
+ if (src->msg && (src->request_position != src->read_position)) {
+#ifdef SEEK_CHANGES
+ if (src->file_size != 0 && src->request_position >= src->file_size) {
+#else
+ if (src->content_size != 0 && src->request_position >= src->content_size) {
+#endif
+ GST_WARNING_OBJECT (src, "Seeking behind the end of file -- EOS");
+ return GST_FLOW_UNEXPECTED;
+ } else if (src->session_io_status ==
+ GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE) {
+ gst_soup_http_src_add_range_header (src, src->request_position);
+ } else {
+ GST_DEBUG_OBJECT (src, "Seek from position %" G_GUINT64_FORMAT
+ " to %" G_GUINT64_FORMAT ": requeueing connection request",
+ src->read_position, src->request_position);
+#ifndef SEEK_CHANGES
+ gst_soup_http_src_cancel_message (src);
+#endif
+ }
+ }
+#ifdef SEEK_CHANGES
+ if(src->msg && src->seeked) {
+ GST_DEBUG_OBJECT (src, "seeking to offset start %llu end %llu", src->request_position, (src->request_position+src->range_size-1));
+ if(src->msg) {
+ soup_session_cancel_message (src->session, src->msg, SOUP_STATUS_OK);
+ src->msg = NULL;
+ if (!gst_soup_http_src_build_message (src))
+ return GST_FLOW_ERROR;
+ }
+ soup_session_queue_message (src->session, src->msg, (SoupSessionCallback) gst_soup_http_src_response_cb, src);
+ src->session_io_status = GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_QUEUED;
+ src->read_position = src->request_position;
+ if(src->range_size > 0) src->content_size = src->request_position+src->range_size-1;
+ else src->content_size = src->file_size;
+ }
+ src->seeked = FALSE;
+#endif
+ if (!src->msg)
+ if (!gst_soup_http_src_build_message (src))
+ return GST_FLOW_ERROR;
+
+ src->ret = GST_FLOW_CUSTOM_ERROR;
+ src->outbuf = outbuf;
+ do {
+ if (src->interrupted) {
+ GST_DEBUG_OBJECT (src, "interrupted");
+ break;
+ }
+ if (src->retry) {
+ GST_DEBUG_OBJECT (src, "Reconnecting");
+ if (!gst_soup_http_src_build_message (src))
+ return GST_FLOW_ERROR;
+ src->retry = FALSE;
+ continue;
+ }
+ if (!src->msg) {
+ GST_DEBUG_OBJECT (src, "EOS reached");
+ break;
+ }
+
+ switch (src->session_io_status) {
+ case GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE:
+ GST_DEBUG_OBJECT (src, "Queueing connection request");
+ gst_soup_http_src_queue_message (src);
+ break;
+ case GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_QUEUED:
+ break;
+ case GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING:
+ gst_soup_http_src_session_unpause_message (src);
+ break;
+ case GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_CANCELLED:
+ /* Impossible. */
+ break;
+ }
+
+ if (src->ret == GST_FLOW_CUSTOM_ERROR)
+ g_main_loop_run (src->loop);
+ } while (src->ret == GST_FLOW_CUSTOM_ERROR);
+
+ if (src->ret == GST_FLOW_CUSTOM_ERROR)
+ src->ret = GST_FLOW_UNEXPECTED;
+ return src->ret;
+}
+
+static gboolean
+gst_soup_http_src_start (GstBaseSrc * bsrc)
+{
+ GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (bsrc);
+
+ GST_DEBUG_OBJECT (src, "start(\"%s\")", src->location);
+
+ if (!src->location) {
+ GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (_("No URL set.")),
+ ("Missing location property"));
+ return FALSE;
+ }
+
+ src->context = g_main_context_new ();
+
+ src->loop = g_main_loop_new (src->context, TRUE);
+ if (!src->loop) {
+ GST_ELEMENT_ERROR (src, LIBRARY, INIT,
+ (NULL), ("Failed to start GMainLoop"));
+ g_main_context_unref (src->context);
+ return FALSE;
+ }
+
+ if (src->proxy == NULL) {
+ src->session =
+ soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
+ src->context, SOUP_SESSION_USER_AGENT, src->user_agent,
+ SOUP_SESSION_TIMEOUT, src->timeout,
+#ifdef HAVE_LIBSOUP_GNOME
+ SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_GNOME,
+#endif
+ NULL);
+ } else {
+ src->session =
+ soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
+ src->context, SOUP_SESSION_PROXY_URI, src->proxy,
+ SOUP_SESSION_TIMEOUT, src->timeout,
+ SOUP_SESSION_USER_AGENT, src->user_agent, NULL);
+ }
+
+ if (!src->session) {
+ GST_ELEMENT_ERROR (src, LIBRARY, INIT,
+ (NULL), ("Failed to create async session"));
+ return FALSE;
+ }
+
+#ifdef GST_EXT_SOUP_MODIFICATION
+ soup_session_add_feature_by_type (src->session, SOUP_TYPE_COOKIE_JAR);
+ src->cookie_jar = SOUP_COOKIE_JAR (soup_session_get_feature (src->session, SOUP_TYPE_COOKIE_JAR));
+#endif
+
+ g_signal_connect (src->session, "authenticate",
+ G_CALLBACK (gst_soup_http_src_authenticate_cb), src);
+ return TRUE;
+}
+
+static gboolean
+gst_soup_http_src_stop (GstBaseSrc * bsrc)
+{
+ GstSoupHTTPSrc *src;
+
+ src = GST_SOUP_HTTP_SRC (bsrc);
+ GST_DEBUG_OBJECT (src, "stop()");
+ gst_soup_http_src_session_close (src);
+ if (src->loop) {
+ g_main_loop_unref (src->loop);
+ g_main_context_unref (src->context);
+ src->loop = NULL;
+ src->context = NULL;
+ }
+ if (src->extra_headers) {
+ gst_structure_free (src->extra_headers);
+ src->extra_headers = NULL;
+ }
+
+ gst_soup_http_src_reset (src);
+ return TRUE;
+}
+
+/* Interrupt a blocking request. */
+static gboolean
+gst_soup_http_src_unlock (GstBaseSrc * bsrc)
+{
+ GstSoupHTTPSrc *src;
+
+ src = GST_SOUP_HTTP_SRC (bsrc);
+ GST_DEBUG_OBJECT (src, "unlock()");
+
+ src->interrupted = TRUE;
+ if (src->loop)
+ g_main_loop_quit (src->loop);
+ return TRUE;
+}
+
+/* Interrupt interrupt. */
+static gboolean
+gst_soup_http_src_unlock_stop (GstBaseSrc * bsrc)
+{
+ GstSoupHTTPSrc *src;
+
+ src = GST_SOUP_HTTP_SRC (bsrc);
+ GST_DEBUG_OBJECT (src, "unlock_stop()");
+
+ src->interrupted = FALSE;
+ return TRUE;
+}
+
+static gboolean
+gst_soup_http_src_get_size (GstBaseSrc * bsrc, guint64 * size)
+{
+ GstSoupHTTPSrc *src;
+
+ src = GST_SOUP_HTTP_SRC (bsrc);
+
+ if (src->have_size) {
+#ifdef SEEK_CHANGES
+ GST_DEBUG_OBJECT (src, "get_size() = %" G_GUINT64_FORMAT,
+ src->file_size);
+ *size = src->file_size;
+#else
+ GST_DEBUG_OBJECT (src, "get_size() = %" G_GUINT64_FORMAT,
+ src->content_size);
+ *size = src->content_size;
+#endif
+ return TRUE;
+ }
+ GST_DEBUG_OBJECT (src, "get_size() = FALSE");
+ return FALSE;
+}
+
+static gboolean
+gst_soup_http_src_is_seekable (GstBaseSrc * bsrc)
+{
+ GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (bsrc);
+
+ return src->seekable;
+}
+
+static gboolean
+gst_soup_http_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
+{
+ GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (bsrc);
+
+ GST_DEBUG_OBJECT (src, "do_seek(%" G_GUINT64_FORMAT ")", segment->start);
+
+#ifdef SEEK_CHANGES
+ src->seeked = TRUE;
+#endif
+ if (src->read_position == segment->start) {
+ GST_DEBUG_OBJECT (src, "Seeking to current read position");
+ return TRUE;
+ }
+
+ if (!src->seekable) {
+ GST_WARNING_OBJECT (src, "Not seekable");
+ return FALSE;
+ }
+
+ if (segment->rate < 0.0 || segment->format != GST_FORMAT_BYTES) {
+ GST_WARNING_OBJECT (src, "Invalid seek segment");
+ return FALSE;
+ }
+
+#ifdef SEEK_CHANGES
+ if (src->content_size != 0 && segment->start >= src->file_size) {
+#else
+ if (src->content_size != 0 && segment->start >= src->content_size) {
+#endif
+ GST_WARNING_OBJECT (src, "Seeking behind end of file, will go to EOS soon");
+ }
+
+ /* Wait for create() to handle the jump in offset. */
+ src->request_position = segment->start;
+ return TRUE;
+}
+
+static gboolean
+gst_soup_http_src_query (GstBaseSrc * bsrc, GstQuery * query)
+{
+ GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (bsrc);
+ gboolean ret;
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_URI:
+ gst_query_set_uri (query, src->location);
+ ret = TRUE;
+ break;
+ default:
+ ret = FALSE;
+ break;
+ }
+
+ if (!ret)
+ ret = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
+
+ return ret;
+}
+
+static gboolean
+gst_soup_http_src_set_location (GstSoupHTTPSrc * src, const gchar * uri)
+{
+ if (src->location) {
+ g_free (src->location);
+ src->location = NULL;
+ }
+ src->location = g_strdup (uri);
+
+ return TRUE;
+}
+
+static gboolean
+gst_soup_http_src_set_proxy (GstSoupHTTPSrc * src, const gchar * uri)
+{
+ if (src->proxy) {
+ soup_uri_free (src->proxy);
+ src->proxy = NULL;
+ }
+ if (g_str_has_prefix (uri, "http://")) {
+ src->proxy = soup_uri_new (uri);
+ } else {
+ gchar *new_uri = g_strconcat ("http://", uri, NULL);
+
+ src->proxy = soup_uri_new (new_uri);
+ g_free (new_uri);
+ }
+
+ return TRUE;
+}
+
+static guint
+gst_soup_http_src_uri_get_type (void)
+{
+ return GST_URI_SRC;
+}
+
+static gchar **
+gst_soup_http_src_uri_get_protocols (void)
+{
+ static const gchar *protocols[] = { "http", "https", NULL };
+ return (gchar **) protocols;
+}
+
+static const gchar *
+gst_soup_http_src_uri_get_uri (GstURIHandler * handler)
+{
+ GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (handler);
+
+ return src->location;
+}
+
+static gboolean
+gst_soup_http_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+{
+ GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (handler);
+
+ return gst_soup_http_src_set_location (src, uri);
+}
+
+static void
+gst_soup_http_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+ GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+ iface->get_type = gst_soup_http_src_uri_get_type;
+ iface->get_protocols = gst_soup_http_src_uri_get_protocols;
+ iface->get_uri = gst_soup_http_src_uri_get_uri;
+ iface->set_uri = gst_soup_http_src_uri_set_uri;
+}
diff --git a/ext/soup/gstsouphttpsrc.h b/ext/soup/gstsouphttpsrc.h
new file mode 100644
index 0000000..95bbc0c
--- /dev/null
+++ b/ext/soup/gstsouphttpsrc.h
@@ -0,0 +1,107 @@
+/* GStreamer
+ * Copyright (C) 2007-2008 Wouter Cloetens <wouter@mind.be>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more
+ */
+
+#ifndef __GST_SOUP_HTTP_SRC_H__
+#define __GST_SOUP_HTTP_SRC_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#include <libsoup/soup.h>
+
+#define GST_TYPE_SOUP_HTTP_SRC \
+ (gst_soup_http_src_get_type())
+#define GST_SOUP_HTTP_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SOUP_HTTP_SRC,GstSoupHTTPSrc))
+#define GST_SOUP_HTTP_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), \
+ GST_TYPE_SOUP_HTTP_SRC,GstSoupHTTPSrcClass))
+#define GST_IS_SOUP_HTTP_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SOUP_HTTP_SRC))
+#define GST_IS_SOUP_HTTP_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SOUP_HTTP_SRC))
+
+typedef struct _GstSoupHTTPSrc GstSoupHTTPSrc;
+typedef struct _GstSoupHTTPSrcClass GstSoupHTTPSrcClass;
+
+typedef enum {
+ GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_IDLE,
+ GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_QUEUED,
+ GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_RUNNING,
+ GST_SOUP_HTTP_SRC_SESSION_IO_STATUS_CANCELLED,
+} GstSoupHTTPSrcSessionIOStatus;
+
+struct _GstSoupHTTPSrc {
+ GstPushSrc element;
+
+ gchar *location; /* Full URI. */
+ gchar *user_agent; /* User-Agent HTTP header. */
+ gboolean automatic_redirect; /* Follow redirects. */
+ SoupURI *proxy; /* HTTP proxy URI. */
+ gchar *user_id; /* Authentication user id for location URI. */
+ gchar *user_pw; /* Authentication user password for location URI. */
+ gchar *proxy_id; /* Authentication user id for proxy URI. */
+ gchar *proxy_pw; /* Authentication user password for proxy URI. */
+ gchar **cookies; /* HTTP request cookies. */
+ GMainContext *context; /* I/O context. */
+ GMainLoop *loop; /* Event loop. */
+ SoupSession *session; /* Async context. */
+ GstSoupHTTPSrcSessionIOStatus session_io_status;
+ /* Async I/O status. */
+ SoupMessage *msg; /* Request message. */
+ GstFlowReturn ret; /* Return code from callback. */
+ GstBuffer **outbuf; /* Return buffer allocated by callback. */
+ gboolean interrupted; /* Signal unlock(). */
+ gboolean retry; /* Should attempt to reconnect. */
+
+ gboolean have_size; /* Received and parsed Content-Length
+ header. */
+ guint64 file_size;
+ gint64 range_size;
+ guint64 content_size; /* Value of Content-Length header. */
+ guint64 read_position; /* Current position. */
+ gboolean seekable; /* FALSE if the server does not support
+ Range. */
+ guint64 request_position; /* Seek to this position. */
+ gboolean seeked;
+
+ /* Shoutcast/icecast metadata extraction handling. */
+ gboolean iradio_mode;
+ GstCaps *src_caps;
+ gchar *iradio_name;
+ gchar *iradio_genre;
+ gchar *iradio_url;
+ gchar *iradio_title;
+
+ GstStructure *extra_headers;
+
+ guint timeout;
+#ifdef GST_EXT_SOUP_MODIFICATION
+ SoupCookieJar *cookie_jar;
+#endif
+};
+
+struct _GstSoupHTTPSrcClass {
+ GstPushSrcClass parent_class;
+};
+
+GType gst_soup_http_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SOUP_HTTP_SRC_H__ */
+
diff --git a/ext/speex/Makefile.am b/ext/speex/Makefile.am
new file mode 100644
index 0000000..fe55237
--- /dev/null
+++ b/ext/speex/Makefile.am
@@ -0,0 +1,18 @@
+plugin_LTLIBRARIES = libgstspeex.la
+
+libgstspeex_la_SOURCES = gstspeex.c gstspeexdec.c gstspeexenc.c
+libgstspeex_la_CFLAGS = -DGST_USE_UNSTABLE_API \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) \
+ $(SPEEX_CFLAGS)
+libgstspeex_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) \
+ -lgsttag-$(GST_MAJORMINOR) -lgstaudio-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS) \
+ $(SPEEX_LIBS)
+libgstspeex_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(LIBM)
+libgstspeex_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstspeexenc.h gstspeexdec.h
diff --git a/ext/speex/Makefile.in b/ext/speex/Makefile.in
new file mode 100644
index 0000000..8f5bcef
--- /dev/null
+++ b/ext/speex/Makefile.in
@@ -0,0 +1,834 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/speex
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstspeex_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgstspeex_la_OBJECTS = libgstspeex_la-gstspeex.lo \
+ libgstspeex_la-gstspeexdec.lo libgstspeex_la-gstspeexenc.lo
+libgstspeex_la_OBJECTS = $(am_libgstspeex_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstspeex_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstspeex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstspeex_la_CFLAGS) $(CFLAGS) \
+ $(libgstspeex_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstspeex_la_SOURCES)
+DIST_SOURCES = $(libgstspeex_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstspeex.la
+libgstspeex_la_SOURCES = gstspeex.c gstspeexdec.c gstspeexenc.c
+libgstspeex_la_CFLAGS = -DGST_USE_UNSTABLE_API \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) \
+ $(SPEEX_CFLAGS)
+
+libgstspeex_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) \
+ -lgsttag-$(GST_MAJORMINOR) -lgstaudio-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS) \
+ $(SPEEX_LIBS)
+
+libgstspeex_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(LIBM)
+libgstspeex_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = gstspeexenc.h gstspeexdec.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/speex/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/speex/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstspeex.la: $(libgstspeex_la_OBJECTS) $(libgstspeex_la_DEPENDENCIES) $(EXTRA_libgstspeex_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstspeex_la_LINK) -rpath $(plugindir) $(libgstspeex_la_OBJECTS) $(libgstspeex_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstspeex_la-gstspeex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstspeex_la-gstspeexdec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstspeex_la-gstspeexenc.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstspeex_la-gstspeex.lo: gstspeex.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstspeex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstspeex_la_CFLAGS) $(CFLAGS) -MT libgstspeex_la-gstspeex.lo -MD -MP -MF $(DEPDIR)/libgstspeex_la-gstspeex.Tpo -c -o libgstspeex_la-gstspeex.lo `test -f 'gstspeex.c' || echo '$(srcdir)/'`gstspeex.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstspeex_la-gstspeex.Tpo $(DEPDIR)/libgstspeex_la-gstspeex.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstspeex.c' object='libgstspeex_la-gstspeex.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstspeex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstspeex_la_CFLAGS) $(CFLAGS) -c -o libgstspeex_la-gstspeex.lo `test -f 'gstspeex.c' || echo '$(srcdir)/'`gstspeex.c
+
+libgstspeex_la-gstspeexdec.lo: gstspeexdec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstspeex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstspeex_la_CFLAGS) $(CFLAGS) -MT libgstspeex_la-gstspeexdec.lo -MD -MP -MF $(DEPDIR)/libgstspeex_la-gstspeexdec.Tpo -c -o libgstspeex_la-gstspeexdec.lo `test -f 'gstspeexdec.c' || echo '$(srcdir)/'`gstspeexdec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstspeex_la-gstspeexdec.Tpo $(DEPDIR)/libgstspeex_la-gstspeexdec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstspeexdec.c' object='libgstspeex_la-gstspeexdec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstspeex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstspeex_la_CFLAGS) $(CFLAGS) -c -o libgstspeex_la-gstspeexdec.lo `test -f 'gstspeexdec.c' || echo '$(srcdir)/'`gstspeexdec.c
+
+libgstspeex_la-gstspeexenc.lo: gstspeexenc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstspeex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstspeex_la_CFLAGS) $(CFLAGS) -MT libgstspeex_la-gstspeexenc.lo -MD -MP -MF $(DEPDIR)/libgstspeex_la-gstspeexenc.Tpo -c -o libgstspeex_la-gstspeexenc.lo `test -f 'gstspeexenc.c' || echo '$(srcdir)/'`gstspeexenc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstspeex_la-gstspeexenc.Tpo $(DEPDIR)/libgstspeex_la-gstspeexenc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstspeexenc.c' object='libgstspeex_la-gstspeexenc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstspeex_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstspeex_la_CFLAGS) $(CFLAGS) -c -o libgstspeex_la-gstspeexenc.lo `test -f 'gstspeexenc.c' || echo '$(srcdir)/'`gstspeexenc.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/speex/gstspeex.c b/ext/speex/gstspeex.c
new file mode 100644
index 0000000..3cd7cbf
--- /dev/null
+++ b/ext/speex/gstspeex.c
@@ -0,0 +1,49 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstspeexdec.h"
+#include "gstspeexenc.h"
+
+#include <gst/tag/tag.h>
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+
+ if (!gst_element_register (plugin, "speexenc", GST_RANK_PRIMARY,
+ GST_TYPE_SPEEX_ENC))
+ return FALSE;
+
+ if (!gst_element_register (plugin, "speexdec", GST_RANK_PRIMARY,
+ GST_TYPE_SPEEX_DEC))
+ return FALSE;
+
+ gst_tag_register_musicbrainz_tags ();
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "speex",
+ "Speex plugin library",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/speex/gstspeexdec.c b/ext/speex/gstspeexdec.c
new file mode 100644
index 0000000..e1d80b6
--- /dev/null
+++ b/ext/speex/gstspeexdec.c
@@ -0,0 +1,549 @@
+/* GStreamer
+ * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-speexdec
+ * @see_also: speexenc, oggdemux
+ *
+ * This element decodes a Speex stream to raw integer audio.
+ * <ulink url="http://www.speex.org/">Speex</ulink> is a royalty-free
+ * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
+ * Foundation</ulink>.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch -v filesrc location=speex.ogg ! oggdemux ! speexdec ! audioconvert ! audioresample ! alsasink
+ * ]| Decode an Ogg/Speex file. To create an Ogg/Speex file refer to the
+ * documentation of speexenc.
+ * </refsect2>
+ *
+ * Last reviewed on 2006-04-05 (0.10.2)
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstspeexdec.h"
+#include <stdlib.h>
+#include <string.h>
+#include <gst/tag/tag.h>
+
+GST_DEBUG_CATEGORY_STATIC (speexdec_debug);
+#define GST_CAT_DEFAULT speexdec_debug
+
+#define DEFAULT_ENH TRUE
+
+enum
+{
+ ARG_0,
+ ARG_ENH
+};
+
+static GstStaticPadTemplate speex_dec_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw-int, "
+ "rate = (int) [ 6000, 48000 ], "
+ "channels = (int) [ 1, 2 ], "
+ "endianness = (int) BYTE_ORDER, "
+ "signed = (boolean) true, " "width = (int) 16, " "depth = (int) 16")
+ );
+
+static GstStaticPadTemplate speex_dec_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-speex")
+ );
+
+GST_BOILERPLATE (GstSpeexDec, gst_speex_dec, GstAudioDecoder,
+ GST_TYPE_AUDIO_DECODER);
+
+
+static gboolean gst_speex_dec_start (GstAudioDecoder * dec);
+static gboolean gst_speex_dec_stop (GstAudioDecoder * dec);
+static gboolean gst_speex_dec_set_format (GstAudioDecoder * bdec,
+ GstCaps * caps);
+static GstFlowReturn gst_speex_dec_handle_frame (GstAudioDecoder * dec,
+ GstBuffer * buffer);
+
+static void gst_speex_dec_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_speex_dec_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static void
+gst_speex_dec_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &speex_dec_src_factory);
+ gst_element_class_add_static_pad_template (element_class,
+ &speex_dec_sink_factory);
+ gst_element_class_set_details_simple (element_class, "Speex audio decoder",
+ "Codec/Decoder/Audio",
+ "decode speex streams to audio", "Wim Taymans <wim@fluendo.com>");
+}
+
+static void
+gst_speex_dec_class_init (GstSpeexDecClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstAudioDecoderClass *base_class;
+
+ gobject_class = (GObjectClass *) klass;
+ base_class = (GstAudioDecoderClass *) klass;
+
+ gobject_class->set_property = gst_speex_dec_set_property;
+ gobject_class->get_property = gst_speex_dec_get_property;
+
+ base_class->start = GST_DEBUG_FUNCPTR (gst_speex_dec_start);
+ base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_dec_stop);
+ base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_dec_set_format);
+ base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_dec_handle_frame);
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ENH,
+ g_param_spec_boolean ("enh", "Enh", "Enable perceptual enhancement",
+ DEFAULT_ENH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ GST_DEBUG_CATEGORY_INIT (speexdec_debug, "speexdec", 0,
+ "speex decoding element");
+}
+
+static void
+gst_speex_dec_reset (GstSpeexDec * dec)
+{
+ dec->packetno = 0;
+ dec->frame_size = 0;
+ dec->frame_duration = 0;
+ dec->mode = NULL;
+ free (dec->header);
+ dec->header = NULL;
+ speex_bits_destroy (&dec->bits);
+
+ gst_buffer_replace (&dec->streamheader, NULL);
+ gst_buffer_replace (&dec->vorbiscomment, NULL);
+
+ if (dec->stereo) {
+ speex_stereo_state_destroy (dec->stereo);
+ dec->stereo = NULL;
+ }
+
+ if (dec->state) {
+ speex_decoder_destroy (dec->state);
+ dec->state = NULL;
+ }
+}
+
+static void
+gst_speex_dec_init (GstSpeexDec * dec, GstSpeexDecClass * g_class)
+{
+ dec->enh = DEFAULT_ENH;
+
+ gst_speex_dec_reset (dec);
+}
+
+static gboolean
+gst_speex_dec_start (GstAudioDecoder * dec)
+{
+ GstSpeexDec *sd = GST_SPEEX_DEC (dec);
+
+ GST_DEBUG_OBJECT (dec, "start");
+ gst_speex_dec_reset (sd);
+
+ /* we know about concealment */
+ gst_audio_decoder_set_plc_aware (dec, TRUE);
+
+ return TRUE;
+}
+
+static gboolean
+gst_speex_dec_stop (GstAudioDecoder * dec)
+{
+ GstSpeexDec *sd = GST_SPEEX_DEC (dec);
+
+ GST_DEBUG_OBJECT (dec, "stop");
+ gst_speex_dec_reset (sd);
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_speex_dec_parse_header (GstSpeexDec * dec, GstBuffer * buf)
+{
+ GstCaps *caps;
+
+ /* get the header */
+ dec->header = speex_packet_to_header ((char *) GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf));
+
+ if (!dec->header)
+ goto no_header;
+
+ if (dec->header->mode >= SPEEX_NB_MODES || dec->header->mode < 0)
+ goto mode_too_old;
+
+ dec->mode = speex_lib_get_mode (dec->header->mode);
+
+ /* initialize the decoder */
+ dec->state = speex_decoder_init (dec->mode);
+ if (!dec->state)
+ goto init_failed;
+
+ speex_decoder_ctl (dec->state, SPEEX_SET_ENH, &dec->enh);
+ speex_decoder_ctl (dec->state, SPEEX_GET_FRAME_SIZE, &dec->frame_size);
+
+ if (dec->header->nb_channels != 1) {
+ dec->stereo = speex_stereo_state_init ();
+ dec->callback.callback_id = SPEEX_INBAND_STEREO;
+ dec->callback.func = speex_std_stereo_request_handler;
+ dec->callback.data = dec->stereo;
+ speex_decoder_ctl (dec->state, SPEEX_SET_HANDLER, &dec->callback);
+ }
+
+ speex_decoder_ctl (dec->state, SPEEX_SET_SAMPLING_RATE, &dec->header->rate);
+
+ dec->frame_duration = gst_util_uint64_scale_int (dec->frame_size,
+ GST_SECOND, dec->header->rate);
+
+ speex_bits_init (&dec->bits);
+
+ /* set caps */
+ caps = gst_caps_new_simple ("audio/x-raw-int",
+ "rate", G_TYPE_INT, dec->header->rate,
+ "channels", G_TYPE_INT, dec->header->nb_channels,
+ "signed", G_TYPE_BOOLEAN, TRUE,
+ "endianness", G_TYPE_INT, G_BYTE_ORDER,
+ "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL);
+
+ if (!gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), caps))
+ goto nego_failed;
+
+ gst_caps_unref (caps);
+ return GST_FLOW_OK;
+
+ /* ERRORS */
+no_header:
+ {
+ GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
+ (NULL), ("couldn't read header"));
+ return GST_FLOW_ERROR;
+ }
+mode_too_old:
+ {
+ GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
+ (NULL),
+ ("Mode number %d does not (yet/any longer) exist in this version",
+ dec->header->mode));
+ return GST_FLOW_ERROR;
+ }
+init_failed:
+ {
+ GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
+ (NULL), ("couldn't initialize decoder"));
+ return GST_FLOW_ERROR;
+ }
+nego_failed:
+ {
+ GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
+ (NULL), ("couldn't negotiate format"));
+ gst_caps_unref (caps);
+ return GST_FLOW_NOT_NEGOTIATED;
+ }
+}
+
+static GstFlowReturn
+gst_speex_dec_parse_comments (GstSpeexDec * dec, GstBuffer * buf)
+{
+ GstTagList *list;
+ gchar *ver, *encoder = NULL;
+
+ list = gst_tag_list_from_vorbiscomment_buffer (buf, NULL, 0, &encoder);
+
+ if (!list) {
+ GST_WARNING_OBJECT (dec, "couldn't decode comments");
+ list = gst_tag_list_new ();
+ }
+
+ if (encoder) {
+ gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+ GST_TAG_ENCODER, encoder, NULL);
+ }
+
+ gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+ GST_TAG_AUDIO_CODEC, "Speex", NULL);
+
+ ver = g_strndup (dec->header->speex_version, SPEEX_HEADER_VERSION_LENGTH);
+ g_strstrip (ver);
+
+ if (ver != NULL && *ver != '\0') {
+ gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+ GST_TAG_ENCODER_VERSION, ver, NULL);
+ }
+
+ if (dec->header->bitrate > 0) {
+ gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+ GST_TAG_BITRATE, (guint) dec->header->bitrate, NULL);
+ }
+
+ GST_INFO_OBJECT (dec, "tags: %" GST_PTR_FORMAT, list);
+
+ gst_element_found_tags_for_pad (GST_ELEMENT (dec),
+ GST_AUDIO_DECODER_SRC_PAD (dec), list);
+
+ g_free (encoder);
+ g_free (ver);
+
+ return GST_FLOW_OK;
+}
+
+static gboolean
+gst_speex_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
+{
+ GstSpeexDec *dec = GST_SPEEX_DEC (bdec);
+ gboolean ret = TRUE;
+ GstStructure *s;
+ const GValue *streamheader;
+
+ s = gst_caps_get_structure (caps, 0);
+ if ((streamheader = gst_structure_get_value (s, "streamheader")) &&
+ G_VALUE_HOLDS (streamheader, GST_TYPE_ARRAY) &&
+ gst_value_array_get_size (streamheader) >= 2) {
+ const GValue *header, *vorbiscomment;
+ GstBuffer *buf;
+ GstFlowReturn res = GST_FLOW_OK;
+
+ header = gst_value_array_get_value (streamheader, 0);
+ if (header && G_VALUE_HOLDS (header, GST_TYPE_BUFFER)) {
+ buf = gst_value_get_buffer (header);
+ res = gst_speex_dec_parse_header (dec, buf);
+ if (res != GST_FLOW_OK)
+ goto done;
+ gst_buffer_replace (&dec->streamheader, buf);
+ }
+
+ vorbiscomment = gst_value_array_get_value (streamheader, 1);
+ if (vorbiscomment && G_VALUE_HOLDS (vorbiscomment, GST_TYPE_BUFFER)) {
+ buf = gst_value_get_buffer (vorbiscomment);
+ res = gst_speex_dec_parse_comments (dec, buf);
+ if (res != GST_FLOW_OK)
+ goto done;
+ gst_buffer_replace (&dec->vorbiscomment, buf);
+ }
+ }
+
+done:
+ return ret;
+}
+
+static GstFlowReturn
+gst_speex_dec_parse_data (GstSpeexDec * dec, GstBuffer * buf)
+{
+ GstFlowReturn res = GST_FLOW_OK;
+ gint i, fpp;
+ guint size;
+ guint8 *data;
+ SpeexBits *bits;
+
+ if (!dec->frame_duration)
+ goto not_negotiated;
+
+ if (G_LIKELY (GST_BUFFER_SIZE (buf))) {
+ data = GST_BUFFER_DATA (buf);
+ size = GST_BUFFER_SIZE (buf);
+
+ /* send data to the bitstream */
+ speex_bits_read_from (&dec->bits, (char *) data, size);
+
+ fpp = dec->header->frames_per_packet;
+ bits = &dec->bits;
+
+ GST_DEBUG_OBJECT (dec, "received buffer of size %u, fpp %d, %d bits",
+ size, fpp, speex_bits_remaining (bits));
+ } else {
+ /* FIXME ? actually consider how much concealment is needed */
+ /* concealment data, pass NULL as the bits parameters */
+ GST_DEBUG_OBJECT (dec, "creating concealment data");
+ fpp = dec->header->frames_per_packet;
+ bits = NULL;
+ }
+
+ /* now decode each frame, catering for unknown number of them (e.g. rtp) */
+ for (i = 0; i < fpp; i++) {
+ GstBuffer *outbuf;
+ gint16 *out_data;
+ gint ret;
+
+ GST_LOG_OBJECT (dec, "decoding frame %d/%d, %d bits remaining", i, fpp,
+ bits ? speex_bits_remaining (bits) : -1);
+
+ res =
+ gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec),
+ GST_BUFFER_OFFSET_NONE, dec->frame_size * dec->header->nb_channels * 2,
+ GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (dec)), &outbuf);
+
+ if (res != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (dec, "buf alloc flow: %s", gst_flow_get_name (res));
+ return res;
+ }
+
+ out_data = (gint16 *) GST_BUFFER_DATA (outbuf);
+
+ ret = speex_decode_int (dec->state, bits, out_data);
+ if (ret == -1) {
+ /* uh? end of stream */
+ if (fpp == 0 && speex_bits_remaining (bits) < 8) {
+ /* if we did not know how many frames to expect, then we get this
+ at the end if there are leftover bits to pad to the next byte */
+ GST_DEBUG_OBJECT (dec, "Discarding leftover bits");
+ } else {
+ GST_WARNING_OBJECT (dec, "Unexpected end of stream found");
+ }
+ gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), NULL, 1);
+ gst_buffer_unref (outbuf);
+ } else if (ret == -2) {
+ GST_WARNING_OBJECT (dec, "Decoding error: corrupted stream?");
+ gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), NULL, 1);
+ gst_buffer_unref (outbuf);
+ }
+
+ if (bits && speex_bits_remaining (bits) < 0) {
+ GST_WARNING_OBJECT (dec, "Decoding overflow: corrupted stream?");
+ gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), NULL, 1);
+ gst_buffer_unref (outbuf);
+ }
+ if (dec->header->nb_channels == 2)
+ speex_decode_stereo_int (out_data, dec->frame_size, dec->stereo);
+
+ res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), outbuf, 1);
+
+ if (res != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (res));
+ break;
+ }
+ }
+
+ return res;
+
+ /* ERRORS */
+not_negotiated:
+ {
+ GST_ELEMENT_ERROR (dec, CORE, NEGOTIATION, (NULL),
+ ("decoder not initialized"));
+ return GST_FLOW_NOT_NEGOTIATED;
+ }
+}
+
+static GstFlowReturn
+gst_speex_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf)
+{
+ GstFlowReturn res;
+ GstSpeexDec *dec;
+
+ /* no fancy draining */
+ if (G_UNLIKELY (!buf))
+ return GST_FLOW_OK;
+
+ dec = GST_SPEEX_DEC (bdec);
+
+ /* If we have the streamheader and vorbiscomment from the caps already
+ * ignore them here */
+ if (dec->streamheader && dec->vorbiscomment) {
+ if (GST_BUFFER_SIZE (dec->streamheader) == GST_BUFFER_SIZE (buf)
+ && memcmp (GST_BUFFER_DATA (dec->streamheader), GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf)) == 0) {
+ GST_DEBUG_OBJECT (dec, "found streamheader");
+ gst_audio_decoder_finish_frame (bdec, NULL, 1);
+ res = GST_FLOW_OK;
+ } else if (GST_BUFFER_SIZE (dec->vorbiscomment) == GST_BUFFER_SIZE (buf)
+ && memcmp (GST_BUFFER_DATA (dec->vorbiscomment), GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf)) == 0) {
+ GST_DEBUG_OBJECT (dec, "found vorbiscomments");
+ gst_audio_decoder_finish_frame (bdec, NULL, 1);
+ res = GST_FLOW_OK;
+ } else {
+ res = gst_speex_dec_parse_data (dec, buf);
+ }
+ } else {
+ /* Otherwise fall back to packet counting and assume that the
+ * first two packets are the headers. */
+ switch (dec->packetno) {
+ case 0:
+ GST_DEBUG_OBJECT (dec, "counted streamheader");
+ res = gst_speex_dec_parse_header (dec, buf);
+ gst_audio_decoder_finish_frame (bdec, NULL, 1);
+ break;
+ case 1:
+ GST_DEBUG_OBJECT (dec, "counted vorbiscomments");
+ res = gst_speex_dec_parse_comments (dec, buf);
+ gst_audio_decoder_finish_frame (bdec, NULL, 1);
+ break;
+ default:
+ {
+ res = gst_speex_dec_parse_data (dec, buf);
+ break;
+ }
+ }
+ }
+
+ dec->packetno++;
+
+ return res;
+}
+
+static void
+gst_speex_dec_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstSpeexDec *speexdec;
+
+ speexdec = GST_SPEEX_DEC (object);
+
+ switch (prop_id) {
+ case ARG_ENH:
+ g_value_set_boolean (value, speexdec->enh);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_speex_dec_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstSpeexDec *speexdec;
+
+ speexdec = GST_SPEEX_DEC (object);
+
+ switch (prop_id) {
+ case ARG_ENH:
+ speexdec->enh = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
diff --git a/ext/speex/gstspeexdec.h b/ext/speex/gstspeexdec.h
new file mode 100644
index 0000000..8187af8
--- /dev/null
+++ b/ext/speex/gstspeexdec.h
@@ -0,0 +1,80 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_SPEEX_DEC_H__
+#define __GST_SPEEX_DEC_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiodecoder.h>
+
+#include <speex/speex.h>
+#include <speex/speex_callbacks.h>
+#include <speex/speex_header.h>
+#include <speex/speex_stereo.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SPEEX_DEC \
+ (gst_speex_dec_get_type())
+#define GST_SPEEX_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPEEX_DEC,GstSpeexDec))
+#define GST_SPEEX_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPEEX_DEC,GstSpeexDecClass))
+#define GST_IS_SPEEX_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPEEX_DEC))
+#define GST_IS_SPEEX_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPEEX_DEC))
+
+typedef struct _GstSpeexDec GstSpeexDec;
+typedef struct _GstSpeexDecClass GstSpeexDecClass;
+
+struct _GstSpeexDec {
+ GstAudioDecoder element;
+
+ void *state;
+ SpeexStereoState *stereo;
+#ifdef SPEEX_1_0
+ SpeexMode *mode;
+#else
+ const SpeexMode *mode;
+#endif
+ SpeexHeader *header;
+ SpeexCallback callback;
+ SpeexBits bits;
+
+ gboolean enh;
+
+ gint frame_size;
+ GstClockTime frame_duration;
+ guint64 packetno;
+
+ GstBuffer *streamheader;
+ GstBuffer *vorbiscomment;
+};
+
+struct _GstSpeexDecClass {
+ GstAudioDecoderClass parent_class;
+};
+
+GType gst_speex_dec_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SPEEX_DEC_H__ */
diff --git a/ext/speex/gstspeexenc.c b/ext/speex/gstspeexenc.c
new file mode 100644
index 0000000..b866e5c
--- /dev/null
+++ b/ext/speex/gstspeexenc.c
@@ -0,0 +1,850 @@
+/* GStreamer Speex Encoder
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-speexenc
+ * @see_also: speexdec, oggmux
+ *
+ * This element encodes audio as a Speex stream.
+ * <ulink url="http://www.speex.org/">Speex</ulink> is a royalty-free
+ * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
+ * Foundation</ulink>.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch audiotestsrc num-buffers=100 ! speexenc ! oggmux ! filesink location=beep.ogg
+ * ]| Encode an Ogg/Speex file.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include <speex/speex.h>
+#include <speex/speex_stereo.h>
+
+#include <gst/gsttagsetter.h>
+#include <gst/tag/tag.h>
+#include <gst/audio/audio.h>
+#include "gstspeexenc.h"
+
+GST_DEBUG_CATEGORY_STATIC (speexenc_debug);
+#define GST_CAT_DEFAULT speexenc_debug
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw-int, "
+ "rate = (int) [ 6000, 48000 ], "
+ "channels = (int) [ 1, 2 ], "
+ "endianness = (int) BYTE_ORDER, "
+ "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16")
+ );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-speex, "
+ "rate = (int) [ 6000, 48000 ], " "channels = (int) [ 1, 2]")
+ );
+
+#define DEFAULT_QUALITY 8.0
+#define DEFAULT_BITRATE 0
+#define DEFAULT_MODE GST_SPEEX_ENC_MODE_AUTO
+#define DEFAULT_VBR FALSE
+#define DEFAULT_ABR 0
+#define DEFAULT_VAD FALSE
+#define DEFAULT_DTX FALSE
+#define DEFAULT_COMPLEXITY 3
+#define DEFAULT_NFRAMES 1
+
+enum
+{
+ PROP_0,
+ PROP_QUALITY,
+ PROP_BITRATE,
+ PROP_MODE,
+ PROP_VBR,
+ PROP_ABR,
+ PROP_VAD,
+ PROP_DTX,
+ PROP_COMPLEXITY,
+ PROP_NFRAMES,
+ PROP_LAST_MESSAGE
+};
+
+#define GST_TYPE_SPEEX_ENC_MODE (gst_speex_enc_mode_get_type())
+static GType
+gst_speex_enc_mode_get_type (void)
+{
+ static GType speex_enc_mode_type = 0;
+ static const GEnumValue speex_enc_modes[] = {
+ {GST_SPEEX_ENC_MODE_AUTO, "Auto", "auto"},
+ {GST_SPEEX_ENC_MODE_UWB, "Ultra Wide Band", "uwb"},
+ {GST_SPEEX_ENC_MODE_WB, "Wide Band", "wb"},
+ {GST_SPEEX_ENC_MODE_NB, "Narrow Band", "nb"},
+ {0, NULL, NULL},
+ };
+ if (G_UNLIKELY (speex_enc_mode_type == 0)) {
+ speex_enc_mode_type = g_enum_register_static ("GstSpeexEncMode",
+ speex_enc_modes);
+ }
+ return speex_enc_mode_type;
+}
+
+static void gst_speex_enc_finalize (GObject * object);
+
+static gboolean gst_speex_enc_setup (GstSpeexEnc * enc);
+
+static void gst_speex_enc_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_speex_enc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf);
+
+static gboolean gst_speex_enc_start (GstAudioEncoder * enc);
+static gboolean gst_speex_enc_stop (GstAudioEncoder * enc);
+static gboolean gst_speex_enc_set_format (GstAudioEncoder * enc,
+ GstAudioInfo * info);
+static GstFlowReturn gst_speex_enc_handle_frame (GstAudioEncoder * enc,
+ GstBuffer * in_buf);
+static gboolean gst_speex_enc_sink_event (GstAudioEncoder * enc,
+ GstEvent * event);
+static GstFlowReturn
+gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer);
+
+static void
+gst_speex_enc_setup_interfaces (GType speexenc_type)
+{
+ static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
+
+ g_type_add_interface_static (speexenc_type, GST_TYPE_TAG_SETTER,
+ &tag_setter_info);
+
+ GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder");
+}
+
+GST_BOILERPLATE_FULL (GstSpeexEnc, gst_speex_enc, GstAudioEncoder,
+ GST_TYPE_AUDIO_ENCODER, gst_speex_enc_setup_interfaces);
+
+static void
+gst_speex_enc_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class, &src_factory);
+ gst_element_class_add_static_pad_template (element_class, &sink_factory);
+ gst_element_class_set_details_simple (element_class, "Speex audio encoder",
+ "Codec/Encoder/Audio",
+ "Encodes audio in Speex format", "Wim Taymans <wim@fluendo.com>");
+}
+
+static void
+gst_speex_enc_class_init (GstSpeexEncClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstAudioEncoderClass *base_class;
+
+ gobject_class = (GObjectClass *) klass;
+ base_class = (GstAudioEncoderClass *) klass;
+
+ gobject_class->set_property = gst_speex_enc_set_property;
+ gobject_class->get_property = gst_speex_enc_get_property;
+
+ base_class->start = GST_DEBUG_FUNCPTR (gst_speex_enc_start);
+ base_class->stop = GST_DEBUG_FUNCPTR (gst_speex_enc_stop);
+ base_class->set_format = GST_DEBUG_FUNCPTR (gst_speex_enc_set_format);
+ base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_speex_enc_handle_frame);
+ base_class->event = GST_DEBUG_FUNCPTR (gst_speex_enc_sink_event);
+ base_class->pre_push = GST_DEBUG_FUNCPTR (gst_speex_enc_pre_push);
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
+ g_param_spec_float ("quality", "Quality", "Encoding quality",
+ 0.0, 10.0, DEFAULT_QUALITY,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
+ g_param_spec_int ("bitrate", "Encoding Bit-rate",
+ "Specify an encoding bit-rate (in bps). (0 = automatic)",
+ 0, G_MAXINT, DEFAULT_BITRATE,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_MODE,
+ g_param_spec_enum ("mode", "Mode", "The encoding mode",
+ GST_TYPE_SPEEX_ENC_MODE, GST_SPEEX_ENC_MODE_AUTO,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VBR,
+ g_param_spec_boolean ("vbr", "VBR",
+ "Enable variable bit-rate", DEFAULT_VBR,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ABR,
+ g_param_spec_int ("abr", "ABR",
+ "Enable average bit-rate (0 = disabled)",
+ 0, G_MAXINT, DEFAULT_ABR,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VAD,
+ g_param_spec_boolean ("vad", "VAD",
+ "Enable voice activity detection", DEFAULT_VAD,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DTX,
+ g_param_spec_boolean ("dtx", "DTX",
+ "Enable discontinuous transmission", DEFAULT_DTX,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COMPLEXITY,
+ g_param_spec_int ("complexity", "Complexity",
+ "Set encoding complexity",
+ 0, G_MAXINT, DEFAULT_COMPLEXITY,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NFRAMES,
+ g_param_spec_int ("nframes", "NFrames",
+ "Number of frames per buffer",
+ 0, G_MAXINT, DEFAULT_NFRAMES,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
+ g_param_spec_string ("last-message", "last-message",
+ "The last status message", NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ gobject_class->finalize = gst_speex_enc_finalize;
+}
+
+static void
+gst_speex_enc_finalize (GObject * object)
+{
+ GstSpeexEnc *enc;
+
+ enc = GST_SPEEX_ENC (object);
+
+ g_free (enc->last_message);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_speex_enc_init (GstSpeexEnc * enc, GstSpeexEncClass * klass)
+{
+ GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);
+
+ /* arrange granulepos marking (and required perfect ts) */
+ gst_audio_encoder_set_mark_granule (benc, TRUE);
+ gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
+}
+
+static gboolean
+gst_speex_enc_start (GstAudioEncoder * benc)
+{
+ GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
+
+ GST_DEBUG_OBJECT (enc, "start");
+ speex_bits_init (&enc->bits);
+ enc->tags = gst_tag_list_new ();
+ enc->header_sent = FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+gst_speex_enc_stop (GstAudioEncoder * benc)
+{
+ GstSpeexEnc *enc = GST_SPEEX_ENC (benc);
+
+ GST_DEBUG_OBJECT (enc, "stop");
+ enc->header_sent = FALSE;
+ if (enc->state) {
+ speex_encoder_destroy (enc->state);
+ enc->state = NULL;
+ }
+ speex_bits_destroy (&enc->bits);
+ gst_tag_list_free (enc->tags);
+ enc->tags = NULL;
+ g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
+ enc->headers = NULL;
+
+ gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
+
+ return TRUE;
+}
+
+static gint64
+gst_speex_enc_get_latency (GstSpeexEnc * enc)
+{
+ /* See the Speex manual section "Latency and algorithmic delay" */
+ if (enc->rate == 8000)
+ return 30 * GST_MSECOND;
+ else
+ return 34 * GST_MSECOND;
+}
+
+static gboolean
+gst_speex_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
+{
+ GstSpeexEnc *enc;
+
+ enc = GST_SPEEX_ENC (benc);
+
+ enc->channels = GST_AUDIO_INFO_CHANNELS (info);
+ enc->rate = GST_AUDIO_INFO_RATE (info);
+
+ /* handle reconfigure */
+ if (enc->state) {
+ speex_encoder_destroy (enc->state);
+ enc->state = NULL;
+ }
+
+ if (!gst_speex_enc_setup (enc))
+ return FALSE;
+
+ /* feedback to base class */
+ gst_audio_encoder_set_latency (benc,
+ gst_speex_enc_get_latency (enc), gst_speex_enc_get_latency (enc));
+ gst_audio_encoder_set_lookahead (benc, enc->lookahead);
+
+ if (enc->nframes == 0) {
+ /* as many frames as available input allows */
+ gst_audio_encoder_set_frame_samples_min (benc, enc->frame_size);
+ gst_audio_encoder_set_frame_samples_max (benc, enc->frame_size);
+ gst_audio_encoder_set_frame_max (benc, 0);
+ } else {
+ /* exactly as many frames as configured */
+ gst_audio_encoder_set_frame_samples_min (benc,
+ enc->frame_size * enc->nframes);
+ gst_audio_encoder_set_frame_samples_max (benc,
+ enc->frame_size * enc->nframes);
+ gst_audio_encoder_set_frame_max (benc, 1);
+ }
+
+ return TRUE;
+}
+
+static GstBuffer *
+gst_speex_enc_create_metadata_buffer (GstSpeexEnc * enc)
+{
+ const GstTagList *user_tags;
+ GstTagList *merged_tags;
+ GstBuffer *comments = NULL;
+
+ user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
+
+ GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
+ GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
+
+ /* gst_tag_list_merge() will handle NULL for either or both lists fine */
+ merged_tags = gst_tag_list_merge (user_tags, enc->tags,
+ gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
+
+ if (merged_tags == NULL)
+ merged_tags = gst_tag_list_new ();
+
+ GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
+ comments = gst_tag_list_to_vorbiscomment_buffer (merged_tags, NULL,
+ 0, "Encoded with GStreamer Speexenc");
+ gst_tag_list_free (merged_tags);
+
+ GST_BUFFER_OFFSET (comments) = 0;
+ GST_BUFFER_OFFSET_END (comments) = 0;
+
+ return comments;
+}
+
+static void
+gst_speex_enc_set_last_msg (GstSpeexEnc * enc, const gchar * msg)
+{
+ g_free (enc->last_message);
+ enc->last_message = g_strdup (msg);
+ GST_WARNING_OBJECT (enc, "%s", msg);
+ g_object_notify (G_OBJECT (enc), "last-message");
+}
+
+static gboolean
+gst_speex_enc_setup (GstSpeexEnc * enc)
+{
+ switch (enc->mode) {
+ case GST_SPEEX_ENC_MODE_UWB:
+ GST_LOG_OBJECT (enc, "configuring for requested UWB mode");
+ enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
+ break;
+ case GST_SPEEX_ENC_MODE_WB:
+ GST_LOG_OBJECT (enc, "configuring for requested WB mode");
+ enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
+ break;
+ case GST_SPEEX_ENC_MODE_NB:
+ GST_LOG_OBJECT (enc, "configuring for requested NB mode");
+ enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
+ break;
+ case GST_SPEEX_ENC_MODE_AUTO:
+ /* fall through */
+ GST_LOG_OBJECT (enc, "finding best mode");
+ default:
+ break;
+ }
+
+ if (enc->rate > 25000) {
+ if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
+ GST_LOG_OBJECT (enc, "selected UWB mode for samplerate %d", enc->rate);
+ enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_UWB);
+ } else {
+ if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_UWB)) {
+ gst_speex_enc_set_last_msg (enc,
+ "Warning: suggest to use ultra wide band mode for this rate");
+ }
+ }
+ } else if (enc->rate > 12500) {
+ if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
+ GST_LOG_OBJECT (enc, "selected WB mode for samplerate %d", enc->rate);
+ enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_WB);
+ } else {
+ if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_WB)) {
+ gst_speex_enc_set_last_msg (enc,
+ "Warning: suggest to use wide band mode for this rate");
+ }
+ }
+ } else {
+ if (enc->mode == GST_SPEEX_ENC_MODE_AUTO) {
+ GST_LOG_OBJECT (enc, "selected NB mode for samplerate %d", enc->rate);
+ enc->speex_mode = speex_lib_get_mode (SPEEX_MODEID_NB);
+ } else {
+ if (enc->speex_mode != speex_lib_get_mode (SPEEX_MODEID_NB)) {
+ gst_speex_enc_set_last_msg (enc,
+ "Warning: suggest to use narrow band mode for this rate");
+ }
+ }
+ }
+
+ if (enc->rate != 8000 && enc->rate != 16000 && enc->rate != 32000) {
+ gst_speex_enc_set_last_msg (enc,
+ "Warning: speex is optimized for 8, 16 and 32 KHz");
+ }
+
+ speex_init_header (&enc->header, enc->rate, 1, enc->speex_mode);
+ enc->header.frames_per_packet = enc->nframes;
+ enc->header.vbr = enc->vbr;
+ enc->header.nb_channels = enc->channels;
+
+ /*Initialize Speex encoder */
+ enc->state = speex_encoder_init (enc->speex_mode);
+
+ speex_encoder_ctl (enc->state, SPEEX_GET_FRAME_SIZE, &enc->frame_size);
+ speex_encoder_ctl (enc->state, SPEEX_SET_COMPLEXITY, &enc->complexity);
+ speex_encoder_ctl (enc->state, SPEEX_SET_SAMPLING_RATE, &enc->rate);
+
+ if (enc->vbr)
+ speex_encoder_ctl (enc->state, SPEEX_SET_VBR_QUALITY, &enc->quality);
+ else {
+ gint tmp = floor (enc->quality);
+
+ speex_encoder_ctl (enc->state, SPEEX_SET_QUALITY, &tmp);
+ }
+ if (enc->bitrate) {
+ if (enc->quality >= 0.0 && enc->vbr) {
+ gst_speex_enc_set_last_msg (enc,
+ "Warning: bitrate option is overriding quality");
+ }
+ speex_encoder_ctl (enc->state, SPEEX_SET_BITRATE, &enc->bitrate);
+ }
+ if (enc->vbr) {
+ gint tmp = 1;
+
+ speex_encoder_ctl (enc->state, SPEEX_SET_VBR, &tmp);
+ } else if (enc->vad) {
+ gint tmp = 1;
+
+ speex_encoder_ctl (enc->state, SPEEX_SET_VAD, &tmp);
+ }
+
+ if (enc->dtx) {
+ gint tmp = 1;
+
+ speex_encoder_ctl (enc->state, SPEEX_SET_DTX, &tmp);
+ }
+
+ if (enc->dtx && !(enc->vbr || enc->abr || enc->vad)) {
+ gst_speex_enc_set_last_msg (enc,
+ "Warning: dtx is useless without vad, vbr or abr");
+ } else if ((enc->vbr || enc->abr) && (enc->vad)) {
+ gst_speex_enc_set_last_msg (enc,
+ "Warning: vad is already implied by vbr or abr");
+ }
+
+ if (enc->abr) {
+ speex_encoder_ctl (enc->state, SPEEX_SET_ABR, &enc->abr);
+ }
+
+ speex_encoder_ctl (enc->state, SPEEX_GET_LOOKAHEAD, &enc->lookahead);
+
+ GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
+ enc->lookahead);
+
+ return TRUE;
+}
+
+/* push out the buffer */
+static GstFlowReturn
+gst_speex_enc_push_buffer (GstSpeexEnc * enc, GstBuffer * buffer)
+{
+ guint size;
+
+ size = GST_BUFFER_SIZE (buffer);
+ GST_DEBUG_OBJECT (enc, "pushing output buffer of size %u", size);
+
+ gst_buffer_set_caps (buffer, GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)));
+ return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buffer);
+}
+
+static gboolean
+gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
+{
+ GstSpeexEnc *enc;
+
+ enc = GST_SPEEX_ENC (benc);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_TAG:
+ {
+ if (enc->tags) {
+ GstTagList *list;
+
+ gst_event_parse_tag (event, &list);
+ gst_tag_list_insert (enc->tags, list,
+ gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
+ } else {
+ g_assert_not_reached ();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* we only peeked, let base class handle it */
+ return FALSE;
+}
+
+static GstFlowReturn
+gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
+{
+ gint frame_size = enc->frame_size;
+ gint bytes = frame_size * 2 * enc->channels, samples, size;
+ gint outsize, written, dtx_ret = 0;
+ guint8 *data, *data0 = NULL;
+ GstBuffer *outbuf;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ if (G_LIKELY (buf)) {
+ data = GST_BUFFER_DATA (buf);
+ size = GST_BUFFER_SIZE (buf);
+
+ if (G_UNLIKELY (size % bytes)) {
+ GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
+ size = ((size / bytes) + 1) * bytes;
+ data0 = data = g_malloc0 (size);
+ memcpy (data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+ }
+ } else {
+ GST_DEBUG_OBJECT (enc, "nothing to drain");
+ goto done;
+ }
+
+ samples = size / (2 * enc->channels);
+ speex_bits_reset (&enc->bits);
+
+ /* FIXME what about dropped samples if DTS enabled ?? */
+
+ while (size) {
+ GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);
+
+ if (enc->channels == 2) {
+ speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
+ }
+ dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);
+
+ data += bytes;
+ size -= bytes;
+ }
+
+ speex_bits_insert_terminator (&enc->bits);
+ outsize = speex_bits_nbytes (&enc->bits);
+
+ ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
+ GST_BUFFER_OFFSET_NONE, outsize,
+ GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
+
+ if ((GST_FLOW_OK != ret))
+ goto done;
+
+ written = speex_bits_write (&enc->bits,
+ (gchar *) GST_BUFFER_DATA (outbuf), outsize);
+
+ if (G_UNLIKELY (written < outsize)) {
+ GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
+ GST_BUFFER_SIZE (outbuf) = written;
+ } else if (G_UNLIKELY (written > outsize)) {
+ GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
+ }
+
+ if (!dtx_ret)
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
+
+ ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
+ outbuf, samples);
+
+done:
+ g_free (data0);
+ return ret;
+}
+
+/*
+ * (really really) FIXME: move into core (dixit tpm)
+ */
+/**
+ * _gst_caps_set_buffer_array:
+ * @caps: a #GstCaps
+ * @field: field in caps to set
+ * @buf: header buffers
+ *
+ * Adds given buffers to an array of buffers set as the given @field
+ * on the given @caps. List of buffer arguments must be NULL-terminated.
+ *
+ * Returns: input caps with a streamheader field added, or NULL if some error
+ */
+static GstCaps *
+_gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
+ GstBuffer * buf, ...)
+{
+ GstStructure *structure = NULL;
+ va_list va;
+ GValue array = { 0 };
+ GValue value = { 0 };
+
+ g_return_val_if_fail (caps != NULL, NULL);
+ g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
+ g_return_val_if_fail (field != NULL, NULL);
+
+ caps = gst_caps_make_writable (caps);
+ structure = gst_caps_get_structure (caps, 0);
+
+ g_value_init (&array, GST_TYPE_ARRAY);
+
+ va_start (va, buf);
+ /* put buffers in a fixed list */
+ while (buf) {
+ g_assert (gst_buffer_is_metadata_writable (buf));
+
+ /* mark buffer */
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+
+ g_value_init (&value, GST_TYPE_BUFFER);
+ buf = gst_buffer_copy (buf);
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+ gst_value_set_buffer (&value, buf);
+ gst_buffer_unref (buf);
+ gst_value_array_append_value (&array, &value);
+ g_value_unset (&value);
+
+ buf = va_arg (va, GstBuffer *);
+ }
+
+ gst_structure_set_value (structure, field, &array);
+ g_value_unset (&array);
+
+ return caps;
+}
+
+static GstFlowReturn
+gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
+{
+ GstSpeexEnc *enc;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ enc = GST_SPEEX_ENC (benc);
+
+ if (!enc->header_sent) {
+ /* Speex streams begin with two headers; the initial header (with
+ most of the codec setup parameters) which is mandated by the Ogg
+ bitstream spec. The second header holds any comment fields.
+ We merely need to make the headers, then pass them to libspeex
+ one at a time; libspeex handles the additional Ogg bitstream
+ constraints */
+ GstBuffer *buf1, *buf2;
+ GstCaps *caps;
+ guchar *data;
+ gint data_len;
+
+ /* create header buffer */
+ data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
+ buf1 = gst_buffer_new ();
+ GST_BUFFER_DATA (buf1) = GST_BUFFER_MALLOCDATA (buf1) = data;
+ GST_BUFFER_SIZE (buf1) = data_len;
+ GST_BUFFER_OFFSET_END (buf1) = 0;
+ GST_BUFFER_OFFSET (buf1) = 0;
+
+ /* create comment buffer */
+ buf2 = gst_speex_enc_create_metadata_buffer (enc);
+
+ /* mark and put on caps */
+ caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT, enc->rate,
+ "channels", G_TYPE_INT, enc->channels, NULL);
+ caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
+
+ /* negotiate with these caps */
+ GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
+
+ gst_buffer_set_caps (buf1, caps);
+ gst_buffer_set_caps (buf2, caps);
+ gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps);
+ gst_caps_unref (caps);
+
+ /* push out buffers */
+ /* store buffers for later pre_push sending */
+ g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
+ enc->headers = NULL;
+ GST_DEBUG_OBJECT (enc, "storing header buffers");
+ enc->headers = g_slist_prepend (enc->headers, buf2);
+ enc->headers = g_slist_prepend (enc->headers, buf1);
+
+ enc->header_sent = TRUE;
+ }
+
+ GST_DEBUG_OBJECT (enc, "received buffer %p of %u bytes", buf,
+ buf ? GST_BUFFER_SIZE (buf) : 0);
+
+ ret = gst_speex_enc_encode (enc, buf);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_speex_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer)
+{
+ GstSpeexEnc *enc;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ enc = GST_SPEEX_ENC (benc);
+
+ /* FIXME 0.11 ? get rid of this special ogg stuff and have it
+ * put and use 'codec data' in caps like anything else,
+ * with all the usual out-of-band advantage etc */
+ if (G_UNLIKELY (enc->headers)) {
+ GSList *header = enc->headers;
+
+ /* try to push all of these, if we lose one, might as well lose all */
+ while (header) {
+ if (ret == GST_FLOW_OK)
+ ret = gst_speex_enc_push_buffer (enc, header->data);
+ else
+ gst_speex_enc_push_buffer (enc, header->data);
+ header = g_slist_next (header);
+ }
+
+ g_slist_free (enc->headers);
+ enc->headers = NULL;
+ }
+
+ return ret;
+}
+
+static void
+gst_speex_enc_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstSpeexEnc *enc;
+
+ enc = GST_SPEEX_ENC (object);
+
+ switch (prop_id) {
+ case PROP_QUALITY:
+ g_value_set_float (value, enc->quality);
+ break;
+ case PROP_BITRATE:
+ g_value_set_int (value, enc->bitrate);
+ break;
+ case PROP_MODE:
+ g_value_set_enum (value, enc->mode);
+ break;
+ case PROP_VBR:
+ g_value_set_boolean (value, enc->vbr);
+ break;
+ case PROP_ABR:
+ g_value_set_int (value, enc->abr);
+ break;
+ case PROP_VAD:
+ g_value_set_boolean (value, enc->vad);
+ break;
+ case PROP_DTX:
+ g_value_set_boolean (value, enc->dtx);
+ break;
+ case PROP_COMPLEXITY:
+ g_value_set_int (value, enc->complexity);
+ break;
+ case PROP_NFRAMES:
+ g_value_set_int (value, enc->nframes);
+ break;
+ case PROP_LAST_MESSAGE:
+ g_value_set_string (value, enc->last_message);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_speex_enc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstSpeexEnc *enc;
+
+ enc = GST_SPEEX_ENC (object);
+
+ switch (prop_id) {
+ case PROP_QUALITY:
+ enc->quality = g_value_get_float (value);
+ break;
+ case PROP_BITRATE:
+ enc->bitrate = g_value_get_int (value);
+ break;
+ case PROP_MODE:
+ enc->mode = g_value_get_enum (value);
+ break;
+ case PROP_VBR:
+ enc->vbr = g_value_get_boolean (value);
+ break;
+ case PROP_ABR:
+ enc->abr = g_value_get_int (value);
+ break;
+ case PROP_VAD:
+ enc->vad = g_value_get_boolean (value);
+ break;
+ case PROP_DTX:
+ enc->dtx = g_value_get_boolean (value);
+ break;
+ case PROP_COMPLEXITY:
+ enc->complexity = g_value_get_int (value);
+ break;
+ case PROP_NFRAMES:
+ enc->nframes = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
diff --git a/ext/speex/gstspeexenc.h b/ext/speex/gstspeexenc.h
new file mode 100644
index 0000000..5cf5cd8
--- /dev/null
+++ b/ext/speex/gstspeexenc.h
@@ -0,0 +1,102 @@
+/* GStreamer Speex Encoder
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_SPEEX_ENC_H__
+#define __GST_SPEEX_ENC_H__
+
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudioencoder.h>
+
+#include <speex/speex.h>
+#include <speex/speex_header.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SPEEX_ENC \
+ (gst_speex_enc_get_type())
+#define GST_SPEEX_ENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPEEX_ENC,GstSpeexEnc))
+#define GST_SPEEX_ENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPEEX_ENC,GstSpeexEncClass))
+#define GST_IS_SPEEX_ENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPEEX_ENC))
+#define GST_IS_SPEEX_ENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPEEX_ENC))
+
+typedef enum
+{
+ GST_SPEEX_ENC_MODE_AUTO,
+ GST_SPEEX_ENC_MODE_UWB,
+ GST_SPEEX_ENC_MODE_WB,
+ GST_SPEEX_ENC_MODE_NB
+} GstSpeexMode;
+
+typedef struct _GstSpeexEnc GstSpeexEnc;
+typedef struct _GstSpeexEncClass GstSpeexEncClass;
+
+struct _GstSpeexEnc {
+ GstAudioEncoder element;
+
+ SpeexBits bits;
+ SpeexHeader header;
+#ifdef SPEEX_1_0
+ SpeexMode *speex_mode;
+#else
+ const SpeexMode *speex_mode;
+#endif
+ void *state;
+
+ /* properties */
+ GstSpeexMode mode;
+ gfloat quality;
+ gint bitrate;
+ gboolean vbr;
+ gint abr;
+ gboolean vad;
+ gboolean dtx;
+ gint complexity;
+ gint nframes;
+ gchar *last_message;
+
+ gint channels;
+ gint rate;
+
+ gboolean header_sent;
+ GSList *headers;
+
+ GstTagList *tags;
+
+ gint frame_size;
+ gint lookahead;
+
+ guint8 *comments;
+ gint comment_len;
+};
+
+struct _GstSpeexEncClass {
+ GstAudioEncoderClass parent_class;
+};
+
+GType gst_speex_enc_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SPEEXENC_H__ */
diff --git a/ext/taglib/Makefile.am b/ext/taglib/Makefile.am
new file mode 100644
index 0000000..75459c5
--- /dev/null
+++ b/ext/taglib/Makefile.am
@@ -0,0 +1,19 @@
+plugin_LTLIBRARIES = libgsttaglib.la
+
+libgsttaglib_la_SOURCES = gsttaglibmux.c gstid3v2mux.cc gstapev2mux.cc
+libgsttaglib_la_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_CFLAGS) \
+ $(TAGLIB_CFLAGS)
+libgsttaglib_la_CXXFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_CXXFLAGS) \
+ $(TAGLIB_CXXFLAGS)
+libgsttaglib_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \
+ $(GST_LIBS) \
+ $(TAGLIB_LIBS)
+libgsttaglib_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgsttaglib_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gsttaglibmux.h gstid3v2mux.h gstapev2mux.h
diff --git a/ext/taglib/Makefile.in b/ext/taglib/Makefile.in
new file mode 100644
index 0000000..4d907c2
--- /dev/null
+++ b/ext/taglib/Makefile.in
@@ -0,0 +1,872 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/taglib
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgsttaglib_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_libgsttaglib_la_OBJECTS = libgsttaglib_la-gsttaglibmux.lo \
+ libgsttaglib_la-gstid3v2mux.lo libgsttaglib_la-gstapev2mux.lo
+libgsttaglib_la_OBJECTS = $(am_libgsttaglib_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgsttaglib_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(libgsttaglib_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CXXLD) $(libgsttaglib_la_CXXFLAGS) $(CXXFLAGS) \
+ $(libgsttaglib_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgsttaglib_la_SOURCES)
+DIST_SOURCES = $(libgsttaglib_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgsttaglib.la
+libgsttaglib_la_SOURCES = gsttaglibmux.c gstid3v2mux.cc gstapev2mux.cc
+libgsttaglib_la_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_CFLAGS) \
+ $(TAGLIB_CFLAGS)
+
+libgsttaglib_la_CXXFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_CXXFLAGS) \
+ $(TAGLIB_CXXFLAGS)
+
+libgsttaglib_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \
+ $(GST_LIBS) \
+ $(TAGLIB_LIBS)
+
+libgsttaglib_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgsttaglib_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = gsttaglibmux.h gstid3v2mux.h gstapev2mux.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/taglib/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/taglib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgsttaglib.la: $(libgsttaglib_la_OBJECTS) $(libgsttaglib_la_DEPENDENCIES) $(EXTRA_libgsttaglib_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libgsttaglib_la_LINK) -rpath $(plugindir) $(libgsttaglib_la_OBJECTS) $(libgsttaglib_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttaglib_la-gstapev2mux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttaglib_la-gstid3v2mux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgsttaglib_la-gsttaglibmux.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgsttaglib_la-gsttaglibmux.lo: gsttaglibmux.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgsttaglib_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttaglib_la_CFLAGS) $(CFLAGS) -MT libgsttaglib_la-gsttaglibmux.lo -MD -MP -MF $(DEPDIR)/libgsttaglib_la-gsttaglibmux.Tpo -c -o libgsttaglib_la-gsttaglibmux.lo `test -f 'gsttaglibmux.c' || echo '$(srcdir)/'`gsttaglibmux.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgsttaglib_la-gsttaglibmux.Tpo $(DEPDIR)/libgsttaglib_la-gsttaglibmux.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gsttaglibmux.c' object='libgsttaglib_la-gsttaglibmux.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgsttaglib_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttaglib_la_CFLAGS) $(CFLAGS) -c -o libgsttaglib_la-gsttaglibmux.lo `test -f 'gsttaglibmux.c' || echo '$(srcdir)/'`gsttaglibmux.c
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+libgsttaglib_la-gstid3v2mux.lo: gstid3v2mux.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(libgsttaglib_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttaglib_la_CXXFLAGS) $(CXXFLAGS) -MT libgsttaglib_la-gstid3v2mux.lo -MD -MP -MF $(DEPDIR)/libgsttaglib_la-gstid3v2mux.Tpo -c -o libgsttaglib_la-gstid3v2mux.lo `test -f 'gstid3v2mux.cc' || echo '$(srcdir)/'`gstid3v2mux.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgsttaglib_la-gstid3v2mux.Tpo $(DEPDIR)/libgsttaglib_la-gstid3v2mux.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gstid3v2mux.cc' object='libgsttaglib_la-gstid3v2mux.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(libgsttaglib_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttaglib_la_CXXFLAGS) $(CXXFLAGS) -c -o libgsttaglib_la-gstid3v2mux.lo `test -f 'gstid3v2mux.cc' || echo '$(srcdir)/'`gstid3v2mux.cc
+
+libgsttaglib_la-gstapev2mux.lo: gstapev2mux.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(libgsttaglib_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttaglib_la_CXXFLAGS) $(CXXFLAGS) -MT libgsttaglib_la-gstapev2mux.lo -MD -MP -MF $(DEPDIR)/libgsttaglib_la-gstapev2mux.Tpo -c -o libgsttaglib_la-gstapev2mux.lo `test -f 'gstapev2mux.cc' || echo '$(srcdir)/'`gstapev2mux.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgsttaglib_la-gstapev2mux.Tpo $(DEPDIR)/libgsttaglib_la-gstapev2mux.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='gstapev2mux.cc' object='libgsttaglib_la-gstapev2mux.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(libgsttaglib_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsttaglib_la_CXXFLAGS) $(CXXFLAGS) -c -o libgsttaglib_la-gstapev2mux.lo `test -f 'gstapev2mux.cc' || echo '$(srcdir)/'`gstapev2mux.cc
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/taglib/gstapev2mux.cc b/ext/taglib/gstapev2mux.cc
new file mode 100644
index 0000000..c99a31f
--- /dev/null
+++ b/ext/taglib/gstapev2mux.cc
@@ -0,0 +1,373 @@
+/* GStreamer taglib-based APEv2 muxer
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-apev2mux
+ * @see_also: #GstTagSetter
+ *
+ * This element adds APEv2 tags to the beginning of a stream using the taglib
+ * library.
+ *
+ * Applications can set the tags to write using the #GstTagSetter interface.
+ * Tags sent by upstream elements will be picked up automatically (and merged
+ * according to the merge mode set via the tag setter interface).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch -v filesrc location=foo.ogg ! decodebin ! audioconvert ! lame ! apev2mux ! filesink location=foo.mp3
+ * ]| A pipeline that transcodes a file from Ogg/Vorbis to mp3 format with an
+ * APEv2 that contains the same as the the Ogg/Vorbis file. Make sure the
+ * Ogg/Vorbis file actually has comments to preserve.
+ * |[
+ * gst-launch -m filesrc location=foo.mp3 ! apedemux ! fakesink silent=TRUE 2&gt; /dev/null | grep taglist
+ * ]| Verify that tags have been written.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstapev2mux.h"
+
+#include <string.h>
+
+#include <apetag.h>
+#include <gst/tag/tag.h>
+
+using namespace TagLib;
+
+GST_DEBUG_CATEGORY_STATIC (gst_apev2_mux_debug);
+#define GST_CAT_DEFAULT gst_apev2_mux_debug
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-apetag"));
+
+GST_BOILERPLATE (GstApev2Mux, gst_apev2_mux, GstTagLibMux,
+ GST_TYPE_TAG_LIB_MUX);
+
+static GstBuffer *gst_apev2_mux_render_tag (GstTagLibMux * mux,
+ GstTagList * taglist);
+
+static void
+gst_apev2_mux_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class, &src_template);
+
+ gst_element_class_set_details_simple (element_class,
+ "TagLib-based APEv2 Muxer", "Formatter/Metadata",
+ "Adds an APEv2 header to the beginning of files using taglib",
+ "Sebastian Dröge <slomo@circular-chaos.org>");
+
+ GST_DEBUG_CATEGORY_INIT (gst_apev2_mux_debug, "apev2mux", 0,
+ "taglib-based APEv2 tag muxer");
+}
+
+static void
+gst_apev2_mux_class_init (GstApev2MuxClass * klass)
+{
+ GST_TAG_LIB_MUX_CLASS (klass)->render_tag =
+ GST_DEBUG_FUNCPTR (gst_apev2_mux_render_tag);
+}
+
+static void
+gst_apev2_mux_init (GstApev2Mux * apev2mux, GstApev2MuxClass * apev2mux_class)
+{
+ /* nothing to do */
+}
+
+static void
+add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
+{
+ APE::Tag * apev2tag = (APE::Tag *) user_data;
+ gboolean result;
+
+ /* FIXME: if there are several values set for the same tag, this won't
+ * work, only the first value will be taken into account
+ */
+ if (strcmp (tag, GST_TAG_TITLE) == 0) {
+ const char *title;
+
+ result = gst_tag_list_peek_string_index (list, tag, 0, &title);
+ if (result != FALSE) {
+ GST_DEBUG ("Setting title to %s", title);
+ apev2tag->setTitle (String (title, String::UTF8));
+ }
+ } else if (strcmp (tag, GST_TAG_ALBUM) == 0) {
+ const char *album;
+
+ result = gst_tag_list_peek_string_index (list, tag, 0, &album);
+ if (result != FALSE) {
+ GST_DEBUG ("Setting album to %s", album);
+ apev2tag->setAlbum (String (album, String::UTF8));
+ }
+ } else if (strcmp (tag, GST_TAG_ARTIST) == 0) {
+ const char *artist;
+
+ result = gst_tag_list_peek_string_index (list, tag, 0, &artist);
+ if (result != FALSE) {
+ GST_DEBUG ("Setting artist to %s", artist);
+ apev2tag->setArtist (String (artist, String::UTF8));
+ }
+ } else if (strcmp (tag, GST_TAG_COMPOSER) == 0) {
+ const char *composer;
+
+ result = gst_tag_list_peek_string_index (list, tag, 0, &composer);
+ if (result != FALSE) {
+ GST_DEBUG ("Setting composer to %s", composer);
+ apev2tag->addValue (String ("COMPOSER", String::UTF8),
+ String (composer, String::UTF8));
+ }
+ } else if (strcmp (tag, GST_TAG_GENRE) == 0) {
+ const char *genre;
+
+ result = gst_tag_list_peek_string_index (list, tag, 0, &genre);
+ if (result != FALSE) {
+ GST_DEBUG ("Setting genre to %s", genre);
+ apev2tag->setGenre (String (genre, String::UTF8));
+ }
+ } else if (strcmp (tag, GST_TAG_COMMENT) == 0) {
+ const char *comment;
+
+ result = gst_tag_list_peek_string_index (list, tag, 0, &comment);
+ if (result != FALSE) {
+ GST_DEBUG ("Setting comment to %s", comment);
+ apev2tag->setComment (String (comment, String::UTF8));
+ }
+ } else if (strcmp (tag, GST_TAG_DATE) == 0) {
+ GDate *date;
+
+ result = gst_tag_list_get_date_index (list, tag, 0, &date);
+ if (result != FALSE) {
+ GDateYear year;
+
+ year = g_date_get_year (date);
+ GST_DEBUG ("Setting track year to %d", year);
+ apev2tag->setYear (year);
+ g_date_free (date);
+ }
+ } else if (strcmp (tag, GST_TAG_TRACK_NUMBER) == 0) {
+ guint track_number;
+
+ result = gst_tag_list_get_uint_index (list, tag, 0, &track_number);
+ if (result != FALSE) {
+ guint total_tracks;
+
+ result = gst_tag_list_get_uint_index (list, GST_TAG_TRACK_COUNT,
+ 0, &total_tracks);
+ if (result) {
+ gchar *tag_str;
+
+ tag_str = g_strdup_printf ("%d/%d", track_number, total_tracks);
+ GST_DEBUG ("Setting track number to %s", tag_str);
+ apev2tag->addValue (String ("TRACK", String::UTF8),
+ String (tag_str, String::UTF8), true);
+ g_free (tag_str);
+ } else {
+ GST_DEBUG ("Setting track number to %d", track_number);
+ apev2tag->setTrack (track_number);
+ }
+ }
+ } else if (strcmp (tag, GST_TAG_TRACK_COUNT) == 0) {
+ guint n;
+
+ if (gst_tag_list_get_uint_index (list, GST_TAG_TRACK_NUMBER, 0, &n)) {
+ GST_DEBUG ("track-count handled with track-number, skipping");
+ } else if (gst_tag_list_get_uint_index (list, GST_TAG_TRACK_COUNT, 0, &n)) {
+ gchar *tag_str;
+
+ tag_str = g_strdup_printf ("0/%d", n);
+ GST_DEBUG ("Setting track number to %s", tag_str);
+ apev2tag->addValue (String ("TRACK", String::UTF8),
+ String (tag_str, String::UTF8), true);
+ g_free (tag_str);
+ }
+#if 0
+ } else if (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0) {
+ guint volume_number;
+
+ result = gst_tag_list_get_uint_index (list, tag, 0, &volume_number);
+
+ if (result != FALSE) {
+ guint volume_count;
+ gchar *tag_str;
+
+ result = gst_tag_list_get_uint_index (list, GST_TAG_ALBUM_VOLUME_COUNT,
+ 0, &volume_count);
+
+ if (result) {
+ tag_str = g_strdup_printf ("CD %d/%d", volume_number, volume_count);
+ } else {
+ tag_str = g_strdup_printf ("CD %d", volume_number);
+ }
+
+ GST_DEBUG ("Setting album number to %s", tag_str);
+
+ apev2tag->addValue (String ("MEDIA", String::UTF8),
+ String (tag_str, String::UTF8), true);
+ g_free (tag_str);
+ }
+ } else if (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0) {
+ guint n;
+
+ if (gst_tag_list_get_uint_index (list, GST_TAG_ALBUM_VOLUME_NUMBER, 0, &n)) {
+ GST_DEBUG ("volume-count handled with volume-number, skipping");
+ } else if (gst_tag_list_get_uint_index (list, GST_TAG_ALBUM_VOLUME_COUNT,
+ 0, &n)) {
+ gchar *tag_str;
+
+ tag_str = g_strdup_printf ("CD 0/%u", n);
+ GST_DEBUG ("Setting album volume number/count to %s", tag_str);
+
+ apev2tag->addValue (String ("MEDIA", String::UTF8),
+ String (tag_str, String::UTF8), true);
+ g_free (tag_str);
+ }
+#endif
+ } else if (strcmp (tag, GST_TAG_COPYRIGHT) == 0) {
+ const gchar *copyright;
+
+ result = gst_tag_list_peek_string_index (list, tag, 0, &copyright);
+
+ if (result != FALSE) {
+ GST_DEBUG ("Setting copyright to %s", copyright);
+ apev2tag->addValue (String ("COPYRIGHT", String::UTF8),
+ String (copyright, String::UTF8), true);
+ }
+ } else if (strcmp (tag, GST_TAG_LOCATION) == 0) {
+ const gchar *location;
+
+ result = gst_tag_list_peek_string_index (list, tag, 0, &location);
+
+ if (result != FALSE) {
+ GST_DEBUG ("Setting location to %s", location);
+ apev2tag->addValue (String ("FILE", String::UTF8),
+ String (location, String::UTF8), true);
+ }
+ } else if (strcmp (tag, GST_TAG_ISRC) == 0) {
+ const gchar *isrc;
+
+ result = gst_tag_list_peek_string_index (list, tag, 0, &isrc);
+
+ if (result != FALSE) {
+ GST_DEBUG ("Setting ISRC to %s", isrc);
+ apev2tag->addValue (String ("ISRC", String::UTF8),
+ String (isrc, String::UTF8), true);
+ }
+ } else if (strcmp (tag, GST_TAG_TRACK_GAIN) == 0) {
+ gdouble value;
+
+ result = gst_tag_list_get_double_index (list, tag, 0, &value);
+
+ if (result != FALSE) {
+ gchar *track_gain = (gchar *) g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
+
+ track_gain = g_ascii_dtostr (track_gain, G_ASCII_DTOSTR_BUF_SIZE, value);
+ GST_DEBUG ("Setting track gain to %s", track_gain);
+ apev2tag->addValue (String ("REPLAYGAIN_TRACK_GAIN",
+ String::UTF8), String (track_gain, String::UTF8), true);
+ g_free (track_gain);
+ }
+ } else if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0) {
+ gdouble value;
+
+ result = gst_tag_list_get_double_index (list, tag, 0, &value);
+
+ if (result != FALSE) {
+ gchar *track_peak = (gchar *) g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
+
+ track_peak = g_ascii_dtostr (track_peak, G_ASCII_DTOSTR_BUF_SIZE, value);
+ GST_DEBUG ("Setting track peak to %s", track_peak);
+ apev2tag->addValue (String ("REPLAYGAIN_TRACK_PEAK",
+ String::UTF8), String (track_peak, String::UTF8), true);
+ g_free (track_peak);
+ }
+ } else if (strcmp (tag, GST_TAG_ALBUM_GAIN) == 0) {
+ gdouble value;
+
+ result = gst_tag_list_get_double_index (list, tag, 0, &value);
+
+ if (result != FALSE) {
+ gchar *album_gain = (gchar *) g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
+
+ album_gain = g_ascii_dtostr (album_gain, G_ASCII_DTOSTR_BUF_SIZE, value);
+ GST_DEBUG ("Setting album gain to %s", album_gain);
+ apev2tag->addValue (String ("REPLAYGAIN_ALBUM_GAIN",
+ String::UTF8), String (album_gain, String::UTF8), true);
+ g_free (album_gain);
+ }
+ } else if (strcmp (tag, GST_TAG_ALBUM_PEAK) == 0) {
+ gdouble value;
+
+ result = gst_tag_list_get_double_index (list, tag, 0, &value);
+
+ if (result != FALSE) {
+ gchar *album_peak = (gchar *) g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
+
+ album_peak = g_ascii_dtostr (album_peak, G_ASCII_DTOSTR_BUF_SIZE, value);
+ GST_DEBUG ("Setting album peak to %s", album_peak);
+ apev2tag->addValue (String ("REPLAYGAIN_ALBUM_PEAK",
+ String::UTF8), String (album_peak, String::UTF8), true);
+ g_free (album_peak);
+ }
+ } else {
+ GST_WARNING ("Unsupported tag: %s", tag);
+ }
+}
+
+static GstBuffer *
+gst_apev2_mux_render_tag (GstTagLibMux * mux, GstTagList * taglist)
+{
+ APE::Tag apev2tag;
+ ByteVector rendered_tag;
+ GstBuffer *buf;
+ guint tag_size;
+
+ /* Render the tag */
+ gst_tag_list_foreach (taglist, add_one_tag, &apev2tag);
+
+ rendered_tag = apev2tag.render ();
+ tag_size = rendered_tag.size ();
+
+ GST_LOG_OBJECT (mux, "tag size = %d bytes", tag_size);
+
+ /* Create buffer with tag */
+ buf = gst_buffer_new_and_alloc (tag_size);
+ memcpy (GST_BUFFER_DATA (buf), rendered_tag.data (), tag_size);
+ gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad));
+
+ return buf;
+}
+
+gboolean
+gst_apev2_mux_plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "apev2mux", GST_RANK_NONE,
+ GST_TYPE_APEV2_MUX))
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/ext/taglib/gstapev2mux.h b/ext/taglib/gstapev2mux.h
new file mode 100644
index 0000000..8dd9333
--- /dev/null
+++ b/ext/taglib/gstapev2mux.h
@@ -0,0 +1,55 @@
+/* GStreamer taglib-based APEv2 muxer
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GST_APEV2_MUX_H
+#define GST_APEV2_MUX_H
+
+#include "gsttaglibmux.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GstApev2Mux GstApev2Mux;
+typedef struct _GstApev2MuxClass GstApev2MuxClass;
+
+struct _GstApev2Mux {
+ GstTagLibMux taglibmux;
+};
+
+struct _GstApev2MuxClass {
+ GstTagLibMuxClass taglibmux_class;
+};
+
+#define GST_TYPE_APEV2_MUX \
+ (gst_apev2_mux_get_type())
+#define GST_APEV2_MUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_APEV2_MUX,GstApev2Mux))
+#define GST_APEV2_MUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_APEV2_MUX,GstApev2MuxClass))
+#define GST_IS_APEV2_MUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_APEV2_MUX))
+#define GST_IS_APEV2_MUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_APEV2_MUX))
+
+GType gst_apev2_mux_get_type (void);
+
+G_END_DECLS
+
+#endif /* GST_APEV2_MUX_H */
diff --git a/ext/taglib/gstid3v2mux.cc b/ext/taglib/gstid3v2mux.cc
new file mode 100644
index 0000000..2b5042e
--- /dev/null
+++ b/ext/taglib/gstid3v2mux.cc
@@ -0,0 +1,775 @@
+/* GStreamer taglib-based ID3v2 muxer
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-id3v2mux
+ * @see_also: #GstID3Demux, #GstTagSetter
+ *
+ * This element adds ID3v2 tags to the beginning of a stream using the taglib
+ * library. More precisely, the tags written are ID3 version 2.4.0 tags (which
+ * means in practice that some hardware players or outdated programs might not
+ * be able to read them properly).
+ *
+ * Applications can set the tags to write using the #GstTagSetter interface.
+ * Tags sent by upstream elements will be picked up automatically (and merged
+ * according to the merge mode set via the tag setter interface).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch -v filesrc location=foo.ogg ! decodebin ! audioconvert ! lame ! id3v2mux ! filesink location=foo.mp3
+ * ]| A pipeline that transcodes a file from Ogg/Vorbis to mp3 format with an
+ * ID3v2 that contains the same as the the Ogg/Vorbis file. Make sure the
+ * Ogg/Vorbis file actually has comments to preserve.
+ * |[
+ * gst-launch -m filesrc location=foo.mp3 ! id3demux ! fakesink silent=TRUE 2&gt; /dev/null | grep taglist
+ * ]| Verify that tags have been written.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstid3v2mux.h"
+
+#include <string.h>
+
+#include <textidentificationframe.h>
+#include <uniquefileidentifierframe.h>
+#include <attachedpictureframe.h>
+#include <relativevolumeframe.h>
+#include <commentsframe.h>
+#include <unknownframe.h>
+#include <id3v2synchdata.h>
+#include <id3v2tag.h>
+#include <gst/tag/tag.h>
+
+using namespace TagLib;
+
+GST_DEBUG_CATEGORY_STATIC (gst_id3v2_mux_debug);
+#define GST_CAT_DEFAULT gst_id3v2_mux_debug
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-id3"));
+
+
+GST_BOILERPLATE (GstId3v2Mux, gst_id3v2_mux, GstTagLibMux,
+ GST_TYPE_TAG_LIB_MUX);
+
+static GstBuffer *gst_id3v2_mux_render_tag (GstTagLibMux * mux,
+ GstTagList * taglist);
+
+static void
+gst_id3v2_mux_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class, &src_template);
+
+ gst_element_class_set_details_simple (element_class,
+ "TagLib-based ID3v2 Muxer", "Formatter/Metadata",
+ "Adds an ID3v2 header to the beginning of MP3 files using taglib",
+ "Christophe Fergeau <teuf@gnome.org>");
+
+ GST_DEBUG_CATEGORY_INIT (gst_id3v2_mux_debug, "id3v2mux", 0,
+ "taglib-based ID3v2 tag muxer");
+}
+
+static void
+gst_id3v2_mux_class_init (GstId3v2MuxClass * klass)
+{
+ GST_TAG_LIB_MUX_CLASS (klass)->render_tag =
+ GST_DEBUG_FUNCPTR (gst_id3v2_mux_render_tag);
+}
+
+static void
+gst_id3v2_mux_init (GstId3v2Mux * id3v2mux, GstId3v2MuxClass * id3v2mux_class)
+{
+ /* nothing to do */
+}
+
+#if 0
+static void
+add_one_txxx_tag (ID3v2::Tag * id3v2tag, const gchar * key, const gchar * val)
+{
+ ID3v2::UserTextIdentificationFrame * frame;
+
+ if (val == NULL)
+ return;
+
+ GST_DEBUG ("Setting %s to %s", key, val);
+ frame = new ID3v2::UserTextIdentificationFrame (String::UTF8);
+ id3v2tag->addFrame (frame);
+ frame->setDescription (key);
+ frame->setText (val);
+}
+#endif
+
+typedef void (*GstId3v2MuxAddTagFunc) (ID3v2::Tag * id3v2tag,
+ const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * data);
+
+static void
+add_encoder_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * unused)
+{
+ TagLib::StringList string_list;
+ guint n;
+
+ /* ENCODER_VERSION is either handled with the ENCODER tag or not at all */
+ if (strcmp (tag, GST_TAG_ENCODER_VERSION) == 0)
+ return;
+
+ for (n = 0; n < num_tags; ++n) {
+ gchar *encoder = NULL;
+
+ if (gst_tag_list_get_string_index (list, tag, n, &encoder) && encoder) {
+ guint encoder_version;
+ gchar *s;
+
+ if (gst_tag_list_get_uint_index (list, GST_TAG_ENCODER_VERSION, n,
+ &encoder_version) && encoder_version > 0) {
+ s = g_strdup_printf ("%s %u", encoder, encoder_version);
+ } else {
+ s = g_strdup (encoder);
+ }
+
+ GST_LOG ("encoder[%u] = '%s'", n, s);
+ string_list.append (String (s, String::UTF8));
+ g_free (s);
+ g_free (encoder);
+ }
+ }
+
+ if (!string_list.isEmpty ()) {
+ ID3v2::TextIdentificationFrame * f;
+
+ f = new ID3v2::TextIdentificationFrame ("TSSE", String::UTF8);
+ id3v2tag->addFrame (f);
+ f->setText (string_list);
+ } else {
+ GST_WARNING ("Empty list for tag %s, skipping", tag);
+ }
+}
+
+static void
+add_date_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * unused)
+{
+ TagLib::StringList string_list;
+ guint n;
+
+ GST_LOG ("Adding date frame");
+
+ for (n = 0; n < num_tags; ++n) {
+ GDate *date = NULL;
+
+ if (gst_tag_list_get_date_index (list, tag, n, &date) && date != NULL) {
+ GDateYear year;
+ gchar *s;
+
+ year = g_date_get_year (date);
+ if (year > 500 && year < 2100) {
+ s = g_strdup_printf ("%u", year);
+ GST_LOG ("%s[%u] = '%s'", tag, n, s);
+ string_list.append (String (s, String::UTF8));
+ g_free (s);
+ } else {
+ GST_WARNING ("invalid year %u, skipping", year);
+ }
+
+ g_date_free (date);
+ }
+ }
+
+ if (!string_list.isEmpty ()) {
+ ID3v2::TextIdentificationFrame * f;
+
+ f = new ID3v2::TextIdentificationFrame ("TDRC", String::UTF8);
+ id3v2tag->addFrame (f);
+ f->setText (string_list);
+ } else {
+ GST_WARNING ("Empty list for tag %s, skipping", tag);
+ }
+}
+
+static void
+add_count_or_num_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+ static const struct
+ {
+ const gchar *gst_tag;
+ const gchar *corr_count; /* corresponding COUNT tag (if number) */
+ const gchar *corr_num; /* corresponding NUMBER tag (if count) */
+ } corr[] = {
+ {
+ GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, NULL}, {
+ GST_TAG_TRACK_COUNT, NULL, GST_TAG_TRACK_NUMBER}, {
+ GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, NULL}, {
+ GST_TAG_ALBUM_VOLUME_COUNT, NULL, GST_TAG_ALBUM_VOLUME_NUMBER}
+ };
+ guint idx;
+
+ for (idx = 0; idx < G_N_ELEMENTS (corr); ++idx) {
+ if (strcmp (corr[idx].gst_tag, tag) == 0)
+ break;
+ }
+
+ g_assert (idx < G_N_ELEMENTS (corr));
+ g_assert (frame_id && strlen (frame_id) == 4);
+
+ if (corr[idx].corr_num == NULL) {
+ guint number;
+
+ /* number tag */
+ if (gst_tag_list_get_uint_index (list, tag, 0, &number)) {
+ ID3v2::TextIdentificationFrame * frame;
+ gchar *tag_str;
+ guint count;
+
+ if (gst_tag_list_get_uint_index (list, corr[idx].corr_count, 0, &count))
+ tag_str = g_strdup_printf ("%u/%u", number, count);
+ else
+ tag_str = g_strdup_printf ("%u", number);
+
+ GST_DEBUG ("Setting %s to %s (frame_id = %s)", tag, tag_str, frame_id);
+ frame = new ID3v2::TextIdentificationFrame (frame_id, String::UTF8);
+ id3v2tag->addFrame (frame);
+ frame->setText (tag_str);
+ g_free (tag_str);
+ }
+ } else if (corr[idx].corr_count == NULL) {
+ guint count;
+
+ /* count tag */
+ if (gst_tag_list_get_uint_index (list, corr[idx].corr_num, 0, &count)) {
+ GST_DEBUG ("%s handled with %s, skipping", tag, corr[idx].corr_num);
+ } else if (gst_tag_list_get_uint_index (list, tag, 0, &count)) {
+ ID3v2::TextIdentificationFrame * frame;
+ gchar *tag_str;
+
+ tag_str = g_strdup_printf ("0/%u", count);
+ GST_DEBUG ("Setting %s to %s (frame_id = %s)", tag, tag_str, frame_id);
+ frame = new ID3v2::TextIdentificationFrame (frame_id, String::UTF8);
+ id3v2tag->addFrame (frame);
+ frame->setText (tag_str);
+ g_free (tag_str);
+ }
+ }
+
+ if (num_tags > 1) {
+ GST_WARNING ("more than one %s, can only handle one", tag);
+ }
+}
+
+static void
+add_unique_file_id_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * unused)
+{
+ const gchar *origin = "http://musicbrainz.org";
+ gchar *id_str = NULL;
+
+ if (gst_tag_list_get_string_index (list, tag, 0, &id_str) && id_str) {
+ ID3v2::UniqueFileIdentifierFrame * frame;
+
+ GST_LOG ("Adding %s (%s): %s", tag, origin, id_str);
+ frame = new ID3v2::UniqueFileIdentifierFrame (origin, id_str);
+ id3v2tag->addFrame (frame);
+ g_free (id_str);
+ }
+}
+
+static void
+add_musicbrainz_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * data)
+{
+ static const struct
+ {
+ const gchar gst_tag[28];
+ const gchar spec_id[28];
+ const gchar realworld_id[28];
+ } mb_ids[] = {
+ {
+ GST_TAG_MUSICBRAINZ_ARTISTID, "MusicBrainz Artist Id",
+ "musicbrainz_artistid"}, {
+ GST_TAG_MUSICBRAINZ_ALBUMID, "MusicBrainz Album Id", "musicbrainz_albumid"}, {
+ GST_TAG_MUSICBRAINZ_ALBUMARTISTID, "MusicBrainz Album Artist Id",
+ "musicbrainz_albumartistid"}, {
+ GST_TAG_MUSICBRAINZ_TRMID, "MusicBrainz TRM Id", "musicbrainz_trmid"}, {
+ GST_TAG_CDDA_MUSICBRAINZ_DISCID, "MusicBrainz DiscID",
+ "musicbrainz_discid"}, {
+ /* the following one is more or less made up, there seems to be little
+ * evidence that any popular application is actually putting this info
+ * into TXXX frames; the first one comes from a musicbrainz wiki 'proposed
+ * tags' page, the second one is analogue to the vorbis/ape/flac tag. */
+ GST_TAG_CDDA_CDDB_DISCID, "CDDB DiscID", "discid"}
+ };
+ guint i, idx;
+
+ idx = (guint8) data[0];
+ g_assert (idx < G_N_ELEMENTS (mb_ids));
+
+ for (i = 0; i < num_tags; ++i) {
+ ID3v2::UserTextIdentificationFrame * frame;
+ gchar *id_str;
+
+ if (gst_tag_list_get_string_index (list, tag, 0, &id_str) && id_str) {
+ GST_DEBUG ("Setting '%s' to '%s'", mb_ids[idx].spec_id, id_str);
+
+ /* add two frames, one with the ID the musicbrainz.org spec mentions
+ * and one with the ID that applications use in the real world */
+ frame = new ID3v2::UserTextIdentificationFrame (String::Latin1);
+ id3v2tag->addFrame (frame);
+ frame->setDescription (mb_ids[idx].spec_id);
+ frame->setText (id_str);
+
+ frame = new ID3v2::UserTextIdentificationFrame (String::Latin1);
+ id3v2tag->addFrame (frame);
+ frame->setDescription (mb_ids[idx].realworld_id);
+ frame->setText (id_str);
+
+ g_free (id_str);
+ }
+ }
+}
+
+static void
+add_id3v2frame_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+ ID3v2::FrameFactory * factory = ID3v2::FrameFactory::instance ();
+ guint i;
+
+ for (i = 0; i < num_tags; ++i) {
+ ID3v2::Frame * frame;
+ const GValue *val;
+ GstBuffer *buf;
+
+ val = gst_tag_list_get_value_index (list, tag, i);
+ buf = (GstBuffer *) gst_value_get_mini_object (val);
+
+ if (buf && GST_BUFFER_CAPS (buf)) {
+ GstStructure *s;
+ gint version = 0;
+
+ s = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0);
+ if (s && gst_structure_get_int (s, "version", &version) && version > 0) {
+ ByteVector bytes ((char *) GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf));
+
+ GST_DEBUG ("Injecting ID3v2.%u frame %u/%u of length %u and type %"
+ GST_PTR_FORMAT, version, i, num_tags, GST_BUFFER_SIZE (buf), s);
+
+ frame = factory->createFrame (bytes, (TagLib::uint) version);
+ if (frame)
+ id3v2tag->addFrame (frame);
+ }
+ }
+ }
+}
+
+static void
+add_image_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * unused)
+{
+ guint n;
+
+ for (n = 0; n < num_tags; ++n) {
+ const GValue *val;
+ GstBuffer *image;
+
+ GST_DEBUG ("image %u/%u", n + 1, num_tags);
+
+ val = gst_tag_list_get_value_index (list, tag, n);
+ image = (GstBuffer *) gst_value_get_mini_object (val);
+
+ if (GST_IS_BUFFER (image) && GST_BUFFER_SIZE (image) > 0 &&
+ GST_BUFFER_CAPS (image) != NULL &&
+ !gst_caps_is_empty (GST_BUFFER_CAPS (image))) {
+ const gchar *mime_type;
+ GstStructure *s;
+
+ s = gst_caps_get_structure (GST_BUFFER_CAPS (image), 0);
+ mime_type = gst_structure_get_name (s);
+ if (mime_type != NULL) {
+ ID3v2::AttachedPictureFrame * frame;
+ const gchar *desc;
+
+ if (strcmp (mime_type, "text/uri-list") == 0)
+ mime_type = "-->";
+
+ frame = new ID3v2::AttachedPictureFrame ();
+
+ GST_DEBUG ("Attaching picture of %u bytes and mime type %s",
+ GST_BUFFER_SIZE (image), mime_type);
+
+ id3v2tag->addFrame (frame);
+ frame->setPicture (ByteVector ((const char *) GST_BUFFER_DATA (image),
+ GST_BUFFER_SIZE (image)));
+ frame->setTextEncoding (String::UTF8);
+ frame->setMimeType (mime_type);
+
+ desc = gst_structure_get_string (s, "image-description");
+ frame->setDescription ((desc) ? desc : "");
+
+ /* FIXME set image type properly from caps */
+ if (strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0) {
+ frame->setType (ID3v2::AttachedPictureFrame::FileIcon);
+ } else {
+ frame->setType (ID3v2::AttachedPictureFrame::Other);
+ }
+ }
+ } else {
+ GST_WARNING ("NULL image or no caps on image buffer (%p, caps=%"
+ GST_PTR_FORMAT ")", image, (image) ? GST_BUFFER_CAPS (image) : NULL);
+ }
+ }
+}
+
+static void
+add_comment_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * unused)
+{
+ TagLib::StringList string_list;
+ guint n;
+
+ GST_LOG ("Adding comment frames");
+ for (n = 0; n < num_tags; ++n) {
+ gchar *s = NULL;
+
+ if (gst_tag_list_get_string_index (list, tag, n, &s) && s != NULL) {
+ ID3v2::CommentsFrame * f;
+ gchar *desc = NULL, *val = NULL, *lang = NULL;
+
+ f = new ID3v2::CommentsFrame (String::UTF8);
+
+ if (strcmp (tag, GST_TAG_COMMENT) == 0 ||
+ !gst_tag_parse_extended_comment (s, &desc, &lang, &val, TRUE)) {
+ /* create dummy description to allow for multiple comment frames
+ * (taglib will drop comment frames if descriptions are not unique) */
+ desc = g_strdup_printf ("c%u", n);
+ val = g_strdup (s);
+ }
+
+ GST_LOG ("%s[%u] = '%s' (%s|%s|%s)", tag, n, s, GST_STR_NULL (desc),
+ GST_STR_NULL (lang), GST_STR_NULL (val));
+
+ f->setDescription (desc);
+ f->setText (val);
+ if (lang) {
+ f->setLanguage (lang);
+ }
+
+ g_free (lang);
+ g_free (desc);
+ g_free (val);
+
+ id3v2tag->addFrame (f);
+ }
+ g_free (s);
+ }
+}
+
+static void
+add_text_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+ ID3v2::TextIdentificationFrame * f;
+ TagLib::StringList string_list;
+ guint n;
+
+ GST_LOG ("Adding '%s' frame", frame_id);
+ for (n = 0; n < num_tags; ++n) {
+ gchar *s = NULL;
+
+ if (gst_tag_list_get_string_index (list, tag, n, &s) && s != NULL) {
+ GST_LOG ("%s: %s[%u] = '%s'", frame_id, tag, n, s);
+ string_list.append (String (s, String::UTF8));
+ g_free (s);
+ }
+ }
+
+ if (!string_list.isEmpty ()) {
+ f = new ID3v2::TextIdentificationFrame (frame_id, String::UTF8);
+ id3v2tag->addFrame (f);
+ f->setText (string_list);
+ } else {
+ GST_WARNING ("Empty list for tag %s, skipping", tag);
+ }
+}
+
+static void
+add_uri_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+ gchar *url = NULL;
+
+ g_assert (frame_id != NULL);
+
+ /* URI tags are limited to one of each per taglist */
+ if (gst_tag_list_get_string_index (list, tag, 0, &url) && url != NULL) {
+ guint url_len;
+
+ url_len = strlen (url);
+ if (url_len > 0 && gst_uri_is_valid (url)) {
+ ID3v2::FrameFactory * factory = ID3v2::FrameFactory::instance ();
+ ID3v2::Frame * frame;
+ char *data;
+
+ data = g_new0 (char, 10 + url_len);
+
+ memcpy (data, frame_id, 4);
+ memcpy (data + 4, ID3v2::SynchData::fromUInt (url_len).data (), 4);
+ memcpy (data + 10, url, url_len);
+ ByteVector bytes (data, 10 + url_len);
+
+ g_free (data);
+
+ frame = factory->createFrame (bytes, (TagLib::uint) 4);
+ if (frame) {
+ id3v2tag->addFrame (frame);
+
+ GST_LOG ("%s: %s = '%s'", frame_id, tag, url);
+ }
+ } else {
+ GST_WARNING ("Tag %s does not contain a valid URI (%s)", tag, url);
+ }
+
+ g_free (url);
+ }
+}
+
+static void
+add_relative_volume_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+ const char *gain_tag_name;
+ const char *peak_tag_name;
+ gdouble peak_val;
+ gdouble gain_val;
+ ID3v2::RelativeVolumeFrame * frame;
+
+ frame = new ID3v2::RelativeVolumeFrame ();
+
+ /* figure out tag names and the identification string to use */
+ if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0 ||
+ strcmp (tag, GST_TAG_TRACK_GAIN) == 0) {
+ gain_tag_name = GST_TAG_TRACK_GAIN;
+ peak_tag_name = GST_TAG_TRACK_PEAK;
+ frame->setIdentification ("track");
+ GST_DEBUG ("adding track relative-volume frame");
+ } else {
+ gain_tag_name = GST_TAG_ALBUM_GAIN;
+ peak_tag_name = GST_TAG_ALBUM_PEAK;
+ frame->setIdentification ("album");
+ GST_DEBUG ("adding album relative-volume frame");
+ }
+
+ /* find the value for the paired tag (gain, if this is peak, and
+ * vice versa). if both tags exist, only write the frame when
+ * we're processing the peak tag.
+ */
+ if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0 ||
+ strcmp (tag, GST_TAG_ALBUM_PEAK) == 0) {
+ ID3v2::RelativeVolumeFrame::PeakVolume encoded_peak;
+ short peak_int;
+
+ gst_tag_list_get_double (list, tag, &peak_val);
+
+ if (gst_tag_list_get_tag_size (list, gain_tag_name) > 0) {
+ gst_tag_list_get_double (list, gain_tag_name, &gain_val);
+ GST_DEBUG ("setting volume adjustment %g", gain_val);
+ frame->setVolumeAdjustment (gain_val);
+ }
+
+ /* copying mutagen: always write as 16 bits for sanity. */
+ peak_int = (short)(peak_val * G_MAXSHORT);
+ encoded_peak.bitsRepresentingPeak = 16;
+ encoded_peak.peakVolume = ByteVector::fromShort(peak_int, true);
+ GST_DEBUG ("setting peak value %g", peak_val);
+ frame->setPeakVolume(encoded_peak);
+
+ } else {
+ gst_tag_list_get_double (list, tag, &gain_val);
+ GST_DEBUG ("setting volume adjustment %g", gain_val);
+ frame->setVolumeAdjustment (gain_val);
+
+ if (gst_tag_list_get_tag_size (list, peak_tag_name) != 0) {
+ GST_DEBUG ("both gain and peak tags exist, not adding frame this time around");
+ delete frame;
+ return;
+ }
+ }
+
+ id3v2tag->addFrame (frame);
+}
+
+static void
+add_bpm_tag (ID3v2::Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+ gdouble bpm;
+
+ if (gst_tag_list_get_double_index (list, tag, 0, &bpm)) {
+ ID3v2::TextIdentificationFrame * frame;
+ gchar *tag_str;
+
+ tag_str = g_strdup_printf ("%u", (guint)bpm);
+
+ GST_DEBUG ("Setting %s to %s", tag, tag_str);
+ frame = new ID3v2::TextIdentificationFrame ("TBPM", String::UTF8);
+ id3v2tag->addFrame (frame);
+ frame->setText (tag_str);
+ g_free (tag_str);
+ }
+}
+
+/* id3demux produces these for frames it cannot parse */
+#define GST_ID3_DEMUX_TAG_ID3V2_FRAME "private-id3v2-frame"
+
+static const struct
+{
+ const gchar *gst_tag;
+ const GstId3v2MuxAddTagFunc func;
+ const gchar data[5];
+} add_funcs[] = {
+ {
+ GST_TAG_ARTIST, add_text_tag, "TPE1"}, {
+ GST_TAG_ALBUM_ARTIST, add_text_tag, "TPE2"}, {
+ GST_TAG_TITLE, add_text_tag, "TIT2"}, {
+ GST_TAG_ALBUM, add_text_tag, "TALB"}, {
+ GST_TAG_COPYRIGHT, add_text_tag, "TCOP"}, {
+ GST_TAG_COMPOSER, add_text_tag, "TCOM"}, {
+ GST_TAG_GENRE, add_text_tag, "TCON"}, {
+ GST_TAG_COMMENT, add_comment_tag, ""}, {
+ GST_TAG_EXTENDED_COMMENT, add_comment_tag, ""}, {
+ GST_TAG_DATE, add_date_tag, ""}, {
+ GST_TAG_IMAGE, add_image_tag, ""}, {
+ GST_TAG_PREVIEW_IMAGE, add_image_tag, ""}, {
+ GST_ID3_DEMUX_TAG_ID3V2_FRAME, add_id3v2frame_tag, ""}, {
+ GST_TAG_MUSICBRAINZ_ARTISTID, add_musicbrainz_tag, "\000"}, {
+ GST_TAG_MUSICBRAINZ_ALBUMID, add_musicbrainz_tag, "\001"}, {
+ GST_TAG_MUSICBRAINZ_ALBUMARTISTID, add_musicbrainz_tag, "\002"}, {
+ GST_TAG_MUSICBRAINZ_TRMID, add_musicbrainz_tag, "\003"}, {
+ GST_TAG_CDDA_MUSICBRAINZ_DISCID, add_musicbrainz_tag, "\004"}, {
+ GST_TAG_CDDA_CDDB_DISCID, add_musicbrainz_tag, "\005"}, {
+ GST_TAG_MUSICBRAINZ_TRACKID, add_unique_file_id_tag, ""}, {
+ GST_TAG_ARTIST_SORTNAME, add_text_tag, "TSOP"}, {
+ GST_TAG_ALBUM_SORTNAME, add_text_tag, "TSOA"}, {
+ GST_TAG_TITLE_SORTNAME, add_text_tag, "TSOT"}, {
+ GST_TAG_TRACK_NUMBER, add_count_or_num_tag, "TRCK"}, {
+ GST_TAG_TRACK_COUNT, add_count_or_num_tag, "TRCK"}, {
+ GST_TAG_ALBUM_VOLUME_NUMBER, add_count_or_num_tag, "TPOS"}, {
+ GST_TAG_ALBUM_VOLUME_COUNT, add_count_or_num_tag, "TPOS"}, {
+ GST_TAG_ENCODER, add_encoder_tag, ""}, {
+ GST_TAG_ENCODER_VERSION, add_encoder_tag, ""}, {
+ GST_TAG_COPYRIGHT_URI, add_uri_tag, "WCOP"}, {
+ GST_TAG_LICENSE_URI, add_uri_tag, "WCOP"}, {
+ GST_TAG_TRACK_PEAK, add_relative_volume_tag, ""}, {
+ GST_TAG_TRACK_GAIN, add_relative_volume_tag, ""}, {
+ GST_TAG_ALBUM_PEAK, add_relative_volume_tag, ""}, {
+ GST_TAG_ALBUM_GAIN, add_relative_volume_tag, ""}, {
+ GST_TAG_BEATS_PER_MINUTE, add_bpm_tag, ""}
+};
+
+
+static void
+foreach_add_tag (const GstTagList * list, const gchar * tag, gpointer userdata)
+{
+ ID3v2::Tag * id3v2tag = (ID3v2::Tag *) userdata;
+ TagLib::StringList string_list;
+ guint num_tags, i;
+
+ num_tags = gst_tag_list_get_tag_size (list, tag);
+
+ GST_LOG ("Processing tag %s (num=%u)", tag, num_tags);
+
+ if (num_tags > 1 && gst_tag_is_fixed (tag)) {
+ GST_WARNING ("Multiple occurences of fixed tag '%s', ignoring some", tag);
+ num_tags = 1;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (add_funcs); ++i) {
+ if (strcmp (add_funcs[i].gst_tag, tag) == 0) {
+ add_funcs[i].func (id3v2tag, list, tag, num_tags, add_funcs[i].data);
+ break;
+ }
+ }
+
+ if (i == G_N_ELEMENTS (add_funcs)) {
+ GST_WARNING ("Unsupported tag '%s' - not written", tag);
+ }
+}
+
+static GstBuffer *
+gst_id3v2_mux_render_tag (GstTagLibMux * mux, GstTagList * taglist)
+{
+ ID3v2::Tag id3v2tag;
+ ByteVector rendered_tag;
+ GstBuffer *buf;
+ guint tag_size;
+
+ /* write all strings as UTF-8 by default */
+ TagLib::ID3v2::FrameFactory::instance ()->
+ setDefaultTextEncoding (TagLib::String::UTF8);
+
+ /* Render the tag */
+ gst_tag_list_foreach (taglist, foreach_add_tag, &id3v2tag);
+
+#if 0
+ /* Do we want to add our own signature to the tag somewhere? */
+ {
+ gchar *tag_producer_str;
+
+ tag_producer_str = g_strdup_printf ("(GStreamer id3v2mux %s, using "
+ "taglib %u.%u)", VERSION, TAGLIB_MAJOR_VERSION, TAGLIB_MINOR_VERSION);
+ add_one_txxx_tag (id3v2tag, "tag_encoder", tag_producer_str);
+ g_free (tag_producer_str);
+ }
+#endif
+
+ rendered_tag = id3v2tag.render ();
+ tag_size = rendered_tag.size ();
+
+ GST_LOG_OBJECT (mux, "tag size = %d bytes", tag_size);
+
+ /* Create buffer with tag */
+ buf = gst_buffer_new_and_alloc (tag_size);
+ memcpy (GST_BUFFER_DATA (buf), rendered_tag.data (), tag_size);
+ gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad));
+
+ return buf;
+}
+
+gboolean
+gst_id3v2_mux_plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "id3v2mux", GST_RANK_NONE,
+ GST_TYPE_ID3V2_MUX))
+ return FALSE;
+
+ gst_tag_register_musicbrainz_tags ();
+
+ return TRUE;
+}
diff --git a/ext/taglib/gstid3v2mux.h b/ext/taglib/gstid3v2mux.h
new file mode 100644
index 0000000..9d47d30
--- /dev/null
+++ b/ext/taglib/gstid3v2mux.h
@@ -0,0 +1,54 @@
+/* GStreamer taglib-based ID3v2 muxer
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GST_ID3V2_MUX_H
+#define GST_ID3V2_MUX_H
+
+#include "gsttaglibmux.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GstId3v2Mux GstId3v2Mux;
+typedef struct _GstId3v2MuxClass GstId3v2MuxClass;
+
+struct _GstId3v2Mux {
+ GstTagLibMux taglibmux;
+};
+
+struct _GstId3v2MuxClass {
+ GstTagLibMuxClass taglibmux_class;
+};
+
+#define GST_TYPE_ID3V2_MUX \
+ (gst_id3v2_mux_get_type())
+#define GST_ID3V2_MUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ID3V2_MUX,GstId3v2Mux))
+#define GST_ID3V2_MUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ID3V2_MUX,GstId3v2MuxClass))
+#define GST_IS_ID3V2_MUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ID3V2_MUX))
+#define GST_IS_ID3V2_MUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ID3V2_MUX))
+
+GType gst_id3v2_mux_get_type (void);
+
+G_END_DECLS
+
+#endif /* GST_ID3V2_MUX_H */
diff --git a/ext/taglib/gsttaglibmux.c b/ext/taglib/gsttaglibmux.c
new file mode 100644
index 0000000..094bec1
--- /dev/null
+++ b/ext/taglib/gsttaglibmux.c
@@ -0,0 +1,402 @@
+/* GStreamer taglib-based muxer base class
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <gst/gsttagsetter.h>
+#include <gst/tag/tag.h>
+
+#include "gsttaglibmux.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_tag_lib_mux_debug);
+#define GST_CAT_DEFAULT gst_tag_lib_mux_debug
+
+static GstStaticPadTemplate gst_tag_lib_mux_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("ANY"));
+
+static void
+gst_tag_lib_mux_iface_init (GType taglib_type)
+{
+ static const GInterfaceInfo tag_setter_info = {
+ NULL,
+ NULL,
+ NULL
+ };
+
+ g_type_add_interface_static (taglib_type, GST_TYPE_TAG_SETTER,
+ &tag_setter_info);
+}
+
+GST_BOILERPLATE_FULL (GstTagLibMux, gst_tag_lib_mux,
+ GstElement, GST_TYPE_ELEMENT, gst_tag_lib_mux_iface_init);
+
+
+static GstStateChangeReturn
+gst_tag_lib_mux_change_state (GstElement * element, GstStateChange transition);
+static GstFlowReturn gst_tag_lib_mux_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_tag_lib_mux_sink_event (GstPad * pad, GstEvent * event);
+
+static void
+gst_tag_lib_mux_finalize (GObject * obj)
+{
+ GstTagLibMux *mux = GST_TAG_LIB_MUX (obj);
+
+ if (mux->newsegment_ev) {
+ gst_event_unref (mux->newsegment_ev);
+ mux->newsegment_ev = NULL;
+ }
+
+ if (mux->event_tags) {
+ gst_tag_list_free (mux->event_tags);
+ mux->event_tags = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_tag_lib_mux_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_tag_lib_mux_sink_template);
+
+ GST_DEBUG_CATEGORY_INIT (gst_tag_lib_mux_debug, "taglibmux", 0,
+ "taglib-based muxer");
+}
+
+static void
+gst_tag_lib_mux_class_init (GstTagLibMuxClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = gst_tag_lib_mux_finalize;
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_tag_lib_mux_change_state);
+}
+
+static void
+gst_tag_lib_mux_init (GstTagLibMux * mux, GstTagLibMuxClass * mux_class)
+{
+ GstElementClass *element_klass = GST_ELEMENT_CLASS (mux_class);
+ GstPadTemplate *tmpl;
+
+ /* pad through which data comes in to the element */
+ mux->sinkpad =
+ gst_pad_new_from_static_template (&gst_tag_lib_mux_sink_template, "sink");
+ gst_pad_set_chain_function (mux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_tag_lib_mux_chain));
+ gst_pad_set_event_function (mux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_tag_lib_mux_sink_event));
+ gst_element_add_pad (GST_ELEMENT (mux), mux->sinkpad);
+
+ /* pad through which data goes out of the element */
+ tmpl = gst_element_class_get_pad_template (element_klass, "src");
+ if (tmpl) {
+ mux->srcpad = gst_pad_new_from_template (tmpl, "src");
+ gst_pad_use_fixed_caps (mux->srcpad);
+ gst_pad_set_caps (mux->srcpad, gst_pad_template_get_caps (tmpl));
+ gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
+ }
+
+ mux->render_tag = TRUE;
+}
+
+static GstBuffer *
+gst_tag_lib_mux_render_tag (GstTagLibMux * mux)
+{
+ GstTagLibMuxClass *klass;
+ GstTagMergeMode merge_mode;
+ GstTagSetter *tagsetter;
+ GstBuffer *buffer;
+ const GstTagList *tagsetter_tags;
+ GstTagList *taglist;
+ GstEvent *event;
+
+ tagsetter = GST_TAG_SETTER (mux);
+
+ tagsetter_tags = gst_tag_setter_get_tag_list (tagsetter);
+ merge_mode = gst_tag_setter_get_tag_merge_mode (tagsetter);
+
+ GST_LOG_OBJECT (mux, "merging tags, merge mode = %d", merge_mode);
+ GST_LOG_OBJECT (mux, "event tags: %" GST_PTR_FORMAT, mux->event_tags);
+ GST_LOG_OBJECT (mux, "set tags: %" GST_PTR_FORMAT, tagsetter_tags);
+
+ taglist = gst_tag_list_merge (tagsetter_tags, mux->event_tags, merge_mode);
+
+ GST_LOG_OBJECT (mux, "final tags: %" GST_PTR_FORMAT, taglist);
+
+ klass = GST_TAG_LIB_MUX_CLASS (G_OBJECT_GET_CLASS (mux));
+
+ if (klass->render_tag == NULL)
+ goto no_vfunc;
+
+ buffer = klass->render_tag (mux, taglist);
+
+ if (buffer == NULL)
+ goto render_error;
+
+ mux->tag_size = GST_BUFFER_SIZE (buffer);
+ GST_LOG_OBJECT (mux, "tag size = %" G_GSIZE_FORMAT " bytes", mux->tag_size);
+
+ /* Send newsegment event from byte position 0, so the tag really gets
+ * written to the start of the file, independent of the upstream segment */
+ gst_pad_push_event (mux->srcpad,
+ gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0));
+
+ /* Send an event about the new tags to downstream elements */
+ /* gst_event_new_tag takes ownership of the list, so no need to unref it */
+ event = gst_event_new_tag (taglist);
+ gst_pad_push_event (mux->srcpad, event);
+
+ GST_BUFFER_OFFSET (buffer) = 0;
+
+ return buffer;
+
+no_vfunc:
+ {
+ GST_ERROR_OBJECT (mux, "Subclass does not implement render_tag vfunc!");
+ gst_tag_list_free (taglist);
+ return NULL;
+ }
+
+render_error:
+ {
+ GST_ERROR_OBJECT (mux, "Failed to render tag");
+ gst_tag_list_free (taglist);
+ return NULL;
+ }
+}
+
+static GstEvent *
+gst_tag_lib_mux_adjust_event_offsets (GstTagLibMux * mux,
+ const GstEvent * newsegment_event)
+{
+ GstFormat format;
+ gint64 start, stop, cur;
+
+ gst_event_parse_new_segment ((GstEvent *) newsegment_event, NULL, NULL,
+ &format, &start, &stop, &cur);
+
+ g_assert (format == GST_FORMAT_BYTES);
+
+ if (start != -1)
+ start += mux->tag_size;
+ if (stop != -1)
+ stop += mux->tag_size;
+ if (cur != -1)
+ cur += mux->tag_size;
+
+ GST_DEBUG_OBJECT (mux, "adjusting newsegment event offsets to start=%"
+ G_GINT64_FORMAT ", stop=%" G_GINT64_FORMAT ", cur=%" G_GINT64_FORMAT
+ " (delta = +%" G_GSIZE_FORMAT ")", start, stop, cur, mux->tag_size);
+
+ return gst_event_new_new_segment (TRUE, 1.0, format, start, stop, cur);
+}
+
+static GstFlowReturn
+gst_tag_lib_mux_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstTagLibMux *mux = GST_TAG_LIB_MUX (GST_OBJECT_PARENT (pad));
+
+ if (mux->render_tag) {
+ GstFlowReturn ret;
+ GstBuffer *tag_buffer;
+
+ GST_INFO_OBJECT (mux, "Adding tags to stream");
+ tag_buffer = gst_tag_lib_mux_render_tag (mux);
+ if (tag_buffer == NULL)
+ goto no_tag_buffer;
+ ret = gst_pad_push (mux->srcpad, tag_buffer);
+ if (ret != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (mux, "flow: %s", gst_flow_get_name (ret));
+ gst_buffer_unref (buffer);
+ return ret;
+ }
+
+ /* Now send the cached newsegment event that we got from upstream */
+ if (mux->newsegment_ev) {
+ GST_DEBUG_OBJECT (mux, "sending cached newsegment event");
+ gst_pad_push_event (mux->srcpad,
+ gst_tag_lib_mux_adjust_event_offsets (mux, mux->newsegment_ev));
+ gst_event_unref (mux->newsegment_ev);
+ mux->newsegment_ev = NULL;
+ } else {
+ /* upstream sent no newsegment event or only one in a non-BYTE format */
+ }
+
+ mux->render_tag = FALSE;
+ }
+
+ buffer = gst_buffer_make_metadata_writable (buffer);
+
+ if (GST_BUFFER_OFFSET (buffer) != GST_BUFFER_OFFSET_NONE) {
+ GST_LOG_OBJECT (mux, "Adjusting buffer offset from %" G_GINT64_FORMAT
+ " to %" G_GINT64_FORMAT, GST_BUFFER_OFFSET (buffer),
+ GST_BUFFER_OFFSET (buffer) + mux->tag_size);
+ GST_BUFFER_OFFSET (buffer) += mux->tag_size;
+ }
+
+ gst_buffer_set_caps (buffer, GST_PAD_CAPS (mux->srcpad));
+ return gst_pad_push (mux->srcpad, buffer);
+
+/* ERRORS */
+no_tag_buffer:
+ {
+ GST_ELEMENT_ERROR (mux, LIBRARY, ENCODE, (NULL), (NULL));
+ return GST_FLOW_ERROR;
+ }
+}
+
+static gboolean
+gst_tag_lib_mux_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstTagLibMux *mux;
+ gboolean result;
+
+ mux = GST_TAG_LIB_MUX (gst_pad_get_parent (pad));
+ result = FALSE;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_TAG:{
+ GstTagList *tags;
+
+ gst_event_parse_tag (event, &tags);
+
+ GST_INFO_OBJECT (mux, "Got tag event: %" GST_PTR_FORMAT, tags);
+
+ if (mux->event_tags != NULL) {
+ gst_tag_list_insert (mux->event_tags, tags, GST_TAG_MERGE_REPLACE);
+ } else {
+ mux->event_tags = gst_tag_list_copy (tags);
+ }
+
+ GST_INFO_OBJECT (mux, "Event tags are now: %" GST_PTR_FORMAT,
+ mux->event_tags);
+
+ /* just drop the event, we'll push a new tag event in render_tag */
+ gst_event_unref (event);
+ result = TRUE;
+ break;
+ }
+ case GST_EVENT_NEWSEGMENT:{
+ GstFormat fmt;
+
+ gst_event_parse_new_segment (event, NULL, NULL, &fmt, NULL, NULL, NULL);
+
+ if (fmt != GST_FORMAT_BYTES) {
+ GST_WARNING_OBJECT (mux, "dropping newsegment event in %s format",
+ gst_format_get_name (fmt));
+ gst_event_unref (event);
+ break;
+ }
+
+ if (mux->render_tag) {
+ /* we have not rendered the tag yet, which means that we don't know
+ * how large it is going to be yet, so we can't adjust the offsets
+ * here at this point and need to cache the newsegment event for now
+ * (also, there could be tag events coming after this newsegment event
+ * and before the first buffer). */
+ if (mux->newsegment_ev) {
+ GST_WARNING_OBJECT (mux, "discarding old cached newsegment event");
+ gst_event_unref (mux->newsegment_ev);
+ }
+
+ GST_LOG_OBJECT (mux, "caching newsegment event for later");
+ mux->newsegment_ev = event;
+ } else {
+ GST_DEBUG_OBJECT (mux, "got newsegment event, adjusting offsets");
+ gst_pad_push_event (mux->srcpad,
+ gst_tag_lib_mux_adjust_event_offsets (mux, event));
+ gst_event_unref (event);
+ }
+ event = NULL;
+ result = TRUE;
+ break;
+ }
+ default:
+ result = gst_pad_event_default (pad, event);
+ break;
+ }
+
+ gst_object_unref (mux);
+
+ return result;
+}
+
+
+static GstStateChangeReturn
+gst_tag_lib_mux_change_state (GstElement * element, GstStateChange transition)
+{
+ GstTagLibMux *mux;
+ GstStateChangeReturn result;
+
+ mux = GST_TAG_LIB_MUX (element);
+
+ result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (result != GST_STATE_CHANGE_SUCCESS) {
+ return result;
+ }
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:{
+ if (mux->newsegment_ev) {
+ gst_event_unref (mux->newsegment_ev);
+ mux->newsegment_ev = NULL;
+ }
+ if (mux->event_tags) {
+ gst_tag_list_free (mux->event_tags);
+ mux->event_tags = NULL;
+ }
+ mux->tag_size = 0;
+ mux->render_tag = TRUE;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return result;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ return (gst_id3v2_mux_plugin_init (plugin)
+ && gst_apev2_mux_plugin_init (plugin));
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "taglib",
+ "Tag writing plug-in based on taglib",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/ext/taglib/gsttaglibmux.h b/ext/taglib/gsttaglibmux.h
new file mode 100644
index 0000000..d26ff30
--- /dev/null
+++ b/ext/taglib/gsttaglibmux.h
@@ -0,0 +1,71 @@
+/* GStreamer taglib-based muxer base class
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GST_TAG_LIB_MUX_H
+#define GST_TAG_LIB_MUX_H
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstTagLibMux GstTagLibMux;
+typedef struct _GstTagLibMuxClass GstTagLibMuxClass;
+
+/* Definition of structure storing data for this element. */
+struct _GstTagLibMux {
+ GstElement element;
+
+ GstPad *srcpad;
+ GstPad *sinkpad;
+ GstTagList *event_tags; /* tags received from upstream elements */
+ gsize tag_size;
+ gboolean render_tag;
+
+ GstEvent *newsegment_ev; /* cached newsegment event from upstream */
+};
+
+/* Standard definition defining a class for this element. */
+struct _GstTagLibMuxClass {
+ GstElementClass parent_class;
+
+ /* vfuncs */
+ GstBuffer * (*render_tag) (GstTagLibMux * mux, GstTagList * tag_list);
+};
+
+/* Standard macros for defining types for this element. */
+#define GST_TYPE_TAG_LIB_MUX \
+ (gst_tag_lib_mux_get_type())
+#define GST_TAG_LIB_MUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TAG_LIB_MUX,GstTagLibMux))
+#define GST_TAG_LIB_MUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TAG_LIB_MUX,GstTagLibMuxClass))
+#define GST_IS_TAG_LIB_MUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TAG_LIB_MUX))
+#define GST_IS_TAG_LIB_MUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TAG_LIB_MUX))
+
+/* Standard function returning type information. */
+GType gst_tag_lib_mux_get_type (void);
+gboolean gst_apev2_mux_plugin_init (GstPlugin * plugin);
+gboolean gst_id3v2_mux_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif
diff --git a/ext/wavpack/Makefile.am b/ext/wavpack/Makefile.am
new file mode 100644
index 0000000..70d2431
--- /dev/null
+++ b/ext/wavpack/Makefile.am
@@ -0,0 +1,24 @@
+plugin_LTLIBRARIES = libgstwavpack.la
+
+libgstwavpack_la_SOURCES = \
+ gstwavpack.c \
+ gstwavpackcommon.c \
+ gstwavpackparse.c \
+ gstwavpackdec.c \
+ gstwavpackenc.c \
+ gstwavpackstreamreader.c
+
+libgstwavpack_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(WAVPACK_CFLAGS)
+libgstwavpack_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) $(GST_LIBS) $(WAVPACK_LIBS)
+libgstwavpack_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstwavpack_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = \
+ gstwavpackparse.h \
+ gstwavpackdec.h \
+ gstwavpackenc.h \
+ gstwavpackcommon.h \
+ gstwavpackstreamreader.h
+
diff --git a/ext/wavpack/Makefile.in b/ext/wavpack/Makefile.in
new file mode 100644
index 0000000..4eb1dd1
--- /dev/null
+++ b/ext/wavpack/Makefile.in
@@ -0,0 +1,868 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/wavpack
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-objc.m4 \
+ $(top_srcdir)/common/m4/as-python.m4 \
+ $(top_srcdir)/common/m4/as-scrub-include.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/esd.m4 \
+ $(top_srcdir)/m4/gconf-2.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstwavpack_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgstwavpack_la_OBJECTS = libgstwavpack_la-gstwavpack.lo \
+ libgstwavpack_la-gstwavpackcommon.lo \
+ libgstwavpack_la-gstwavpackparse.lo \
+ libgstwavpack_la-gstwavpackdec.lo \
+ libgstwavpack_la-gstwavpackenc.lo \
+ libgstwavpack_la-gstwavpackstreamreader.lo
+libgstwavpack_la_OBJECTS = $(am_libgstwavpack_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+libgstwavpack_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstwavpack_la_CFLAGS) $(CFLAGS) \
+ $(libgstwavpack_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgstwavpack_la_SOURCES)
+DIST_SOURCES = $(libgstwavpack_la_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ANNODEX_CFLAGS = @ANNODEX_CFLAGS@
+ANNODEX_LIBS = @ANNODEX_LIBS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_GOBJECT_CFLAGS = @CAIRO_GOBJECT_CFLAGS@
+CAIRO_GOBJECT_LIBS = @CAIRO_GOBJECT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ESD_CFLAGS = @ESD_CFLAGS@
+ESD_CONFIG = @ESD_CONFIG@
+ESD_LIBS = @ESD_LIBS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCONFTOOL = @GCONFTOOL@
+GCONF_CFLAGS = @GCONF_CFLAGS@
+GCONF_LIBS = @GCONF_LIBS@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_GDP_CFLAGS = @GST_GDP_CFLAGS@
+GST_GDP_LIBS = @GST_GDP_LIBS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_MAJORMINOR = @GST_MAJORMINOR@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAL_CFLAGS = @HAL_CFLAGS@
+HAL_LIBS = @HAL_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_BZ2 = @HAVE_BZ2@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_GCONFTOOL = @HAVE_GCONFTOOL@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJC_LDFLAGS = @OBJC_LDFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_0_9_20_CFLAGS = @PULSE_0_9_20_CFLAGS@
+PULSE_0_9_20_LIBS = @PULSE_0_9_20_LIBS@
+PULSE_1_0_CFLAGS = @PULSE_1_0_CFLAGS@
+PULSE_1_0_LIBS = @PULSE_1_0_LIBS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+WIN32_LIBS = @WIN32_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+XVIDEO_LIBS = @XVIDEO_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstwavpack.la
+libgstwavpack_la_SOURCES = \
+ gstwavpack.c \
+ gstwavpackcommon.c \
+ gstwavpackparse.c \
+ gstwavpackdec.c \
+ gstwavpackenc.c \
+ gstwavpackstreamreader.c
+
+libgstwavpack_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(WAVPACK_CFLAGS)
+
+libgstwavpack_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
+ $(GST_BASE_LIBS) $(GST_LIBS) $(WAVPACK_LIBS)
+
+libgstwavpack_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstwavpack_la_LIBTOOLFLAGS = --tag=disable-static
+noinst_HEADERS = \
+ gstwavpackparse.h \
+ gstwavpackdec.h \
+ gstwavpackenc.h \
+ gstwavpackcommon.h \
+ gstwavpackstreamreader.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ext/wavpack/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ext/wavpack/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgstwavpack.la: $(libgstwavpack_la_OBJECTS) $(libgstwavpack_la_DEPENDENCIES) $(EXTRA_libgstwavpack_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstwavpack_la_LINK) -rpath $(plugindir) $(libgstwavpack_la_OBJECTS) $(libgstwavpack_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstwavpack_la-gstwavpack.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstwavpack_la-gstwavpackcommon.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstwavpack_la-gstwavpackdec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstwavpack_la-gstwavpackenc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstwavpack_la-gstwavpackparse.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstwavpack_la-gstwavpackstreamreader.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstwavpack_la-gstwavpack.lo: gstwavpack.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwavpack_la_CFLAGS) $(CFLAGS) -MT libgstwavpack_la-gstwavpack.lo -MD -MP -MF $(DEPDIR)/libgstwavpack_la-gstwavpack.Tpo -c -o libgstwavpack_la-gstwavpack.lo `test -f 'gstwavpack.c' || echo '$(srcdir)/'`gstwavpack.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstwavpack_la-gstwavpack.Tpo $(DEPDIR)/libgstwavpack_la-gstwavpack.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstwavpack.c' object='libgstwavpack_la-gstwavpack.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwavpack_la_CFLAGS) $(CFLAGS) -c -o libgstwavpack_la-gstwavpack.lo `test -f 'gstwavpack.c' || echo '$(srcdir)/'`gstwavpack.c
+
+libgstwavpack_la-gstwavpackcommon.lo: gstwavpackcommon.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwavpack_la_CFLAGS) $(CFLAGS) -MT libgstwavpack_la-gstwavpackcommon.lo -MD -MP -MF $(DEPDIR)/libgstwavpack_la-gstwavpackcommon.Tpo -c -o libgstwavpack_la-gstwavpackcommon.lo `test -f 'gstwavpackcommon.c' || echo '$(srcdir)/'`gstwavpackcommon.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstwavpack_la-gstwavpackcommon.Tpo $(DEPDIR)/libgstwavpack_la-gstwavpackcommon.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstwavpackcommon.c' object='libgstwavpack_la-gstwavpackcommon.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwavpack_la_CFLAGS) $(CFLAGS) -c -o libgstwavpack_la-gstwavpackcommon.lo `test -f 'gstwavpackcommon.c' || echo '$(srcdir)/'`gstwavpackcommon.c
+
+libgstwavpack_la-gstwavpackparse.lo: gstwavpackparse.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwavpack_la_CFLAGS) $(CFLAGS) -MT libgstwavpack_la-gstwavpackparse.lo -MD -MP -MF $(DEPDIR)/libgstwavpack_la-gstwavpackparse.Tpo -c -o libgstwavpack_la-gstwavpackparse.lo `test -f 'gstwavpackparse.c' || echo '$(srcdir)/'`gstwavpackparse.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstwavpack_la-gstwavpackparse.Tpo $(DEPDIR)/libgstwavpack_la-gstwavpackparse.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstwavpackparse.c' object='libgstwavpack_la-gstwavpackparse.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwavpack_la_CFLAGS) $(CFLAGS) -c -o libgstwavpack_la-gstwavpackparse.lo `test -f 'gstwavpackparse.c' || echo '$(srcdir)/'`gstwavpackparse.c
+
+libgstwavpack_la-gstwavpackdec.lo: gstwavpackdec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwavpack_la_CFLAGS) $(CFLAGS) -MT libgstwavpack_la-gstwavpackdec.lo -MD -MP -MF $(DEPDIR)/libgstwavpack_la-gstwavpackdec.Tpo -c -o libgstwavpack_la-gstwavpackdec.lo `test -f 'gstwavpackdec.c' || echo '$(srcdir)/'`gstwavpackdec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstwavpack_la-gstwavpackdec.Tpo $(DEPDIR)/libgstwavpack_la-gstwavpackdec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstwavpackdec.c' object='libgstwavpack_la-gstwavpackdec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwavpack_la_CFLAGS) $(CFLAGS) -c -o libgstwavpack_la-gstwavpackdec.lo `test -f 'gstwavpackdec.c' || echo '$(srcdir)/'`gstwavpackdec.c
+
+libgstwavpack_la-gstwavpackenc.lo: gstwavpackenc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwavpack_la_CFLAGS) $(CFLAGS) -MT libgstwavpack_la-gstwavpackenc.lo -MD -MP -MF $(DEPDIR)/libgstwavpack_la-gstwavpackenc.Tpo -c -o libgstwavpack_la-gstwavpackenc.lo `test -f 'gstwavpackenc.c' || echo '$(srcdir)/'`gstwavpackenc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstwavpack_la-gstwavpackenc.Tpo $(DEPDIR)/libgstwavpack_la-gstwavpackenc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstwavpackenc.c' object='libgstwavpack_la-gstwavpackenc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwavpack_la_CFLAGS) $(CFLAGS) -c -o libgstwavpack_la-gstwavpackenc.lo `test -f 'gstwavpackenc.c' || echo '$(srcdir)/'`gstwavpackenc.c
+
+libgstwavpack_la-gstwavpackstreamreader.lo: gstwavpackstreamreader.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwavpack_la_CFLAGS) $(CFLAGS) -MT libgstwavpack_la-gstwavpackstreamreader.lo -MD -MP -MF $(DEPDIR)/libgstwavpack_la-gstwavpackstreamreader.Tpo -c -o libgstwavpack_la-gstwavpackstreamreader.lo `test -f 'gstwavpackstreamreader.c' || echo '$(srcdir)/'`gstwavpackstreamreader.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstwavpack_la-gstwavpackstreamreader.Tpo $(DEPDIR)/libgstwavpack_la-gstwavpackstreamreader.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstwavpackstreamreader.c' object='libgstwavpack_la-gstwavpackstreamreader.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwavpack_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwavpack_la_CFLAGS) $(CFLAGS) -c -o libgstwavpack_la-gstwavpackstreamreader.lo `test -f 'gstwavpackstreamreader.c' || echo '$(srcdir)/'`gstwavpackstreamreader.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ext/wavpack/gstwavpack.c b/ext/wavpack/gstwavpack.c
new file mode 100644
index 0000000..b01f443
--- /dev/null
+++ b/ext/wavpack/gstwavpack.c
@@ -0,0 +1,56 @@
+/* GStreamer wavpack plugin
+ * (c) 2004 Arwed v. Merkatz <v.merkatz@gmx.net>
+ *
+ * gstwavpack.c: plugin loader
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst-i18n-plugin.h>
+
+#include "gstwavpackparse.h"
+#include "gstwavpackdec.h"
+#include "gstwavpackenc.h"
+
+/* debug category for common code */
+GST_DEBUG_CATEGORY (wavpack_debug);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (wavpack_debug, "wavpack", 0, "Wavpack elements");
+
+#ifdef ENABLE_NLS
+ GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+ LOCALEDIR);
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+ return (gst_wavpack_parse_plugin_init (plugin)
+ && gst_wavpack_dec_plugin_init (plugin)
+ && gst_wavpack_enc_plugin_init (plugin));
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "wavpack",
+ "Wavpack lossless/lossy audio format handling",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/wavpack/gstwavpackcommon.c b/ext/wavpack/gstwavpackcommon.c
new file mode 100644
index 0000000..252b64c
--- /dev/null
+++ b/ext/wavpack/gstwavpackcommon.c
@@ -0,0 +1,282 @@
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (c) 1998 - 2005 Conifer Software
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackcommon.c: common helper functions
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstwavpackcommon.h"
+#include <string.h>
+
+#include <gst/gst.h>
+#include <gst/audio/multichannel.h>
+
+GST_DEBUG_CATEGORY_EXTERN (wavpack_debug);
+#define GST_CAT_DEFAULT wavpack_debug
+
+gboolean
+gst_wavpack_read_header (WavpackHeader * header, guint8 * buf)
+{
+ g_memmove (header, buf, sizeof (WavpackHeader));
+
+#ifndef WAVPACK_OLD_API
+ WavpackLittleEndianToNative (header, (char *) WavpackHeaderFormat);
+#else
+ little_endian_to_native (header, WavpackHeaderFormat);
+#endif
+
+ return (memcmp (header->ckID, "wvpk", 4) == 0);
+}
+
+/* inspired by the original one in wavpack */
+gboolean
+gst_wavpack_read_metadata (GstWavpackMetadata * wpmd, guint8 * header_data,
+ guint8 ** p_data)
+{
+ WavpackHeader hdr;
+ guint8 *end;
+
+ gst_wavpack_read_header (&hdr, header_data);
+ end = header_data + hdr.ckSize + 8;
+
+ if (end - *p_data < 2)
+ return FALSE;
+
+ wpmd->id = GST_READ_UINT8 (*p_data);
+ wpmd->byte_length = 2 * (guint) GST_READ_UINT8 (*p_data + 1);
+
+ *p_data += 2;
+
+ if ((wpmd->id & ID_LARGE) == ID_LARGE) {
+ guint extra;
+
+ wpmd->id &= ~ID_LARGE;
+
+ if (end - *p_data < 2)
+ return FALSE;
+
+ extra = GST_READ_UINT16_LE (*p_data);
+ wpmd->byte_length += (extra << 9);
+ *p_data += 2;
+ }
+
+ if ((wpmd->id & ID_ODD_SIZE) == ID_ODD_SIZE) {
+ wpmd->id &= ~ID_ODD_SIZE;
+ --wpmd->byte_length;
+ }
+
+ if (wpmd->byte_length > 0) {
+ if (end - *p_data < wpmd->byte_length + (wpmd->byte_length & 1)) {
+ wpmd->data = NULL;
+ return FALSE;
+ }
+
+ wpmd->data = *p_data;
+ *p_data += wpmd->byte_length + (wpmd->byte_length & 1);
+ } else {
+ wpmd->data = NULL;
+ }
+
+ return TRUE;
+}
+
+gint
+gst_wavpack_get_default_channel_mask (gint nchannels)
+{
+ gint channel_mask = 0;
+
+ /* Set the default channel mask for the given number of channels.
+ * It's the same as for WAVE_FORMAT_EXTENDED:
+ * http://www.microsoft.com/whdc/device/audio/multichaud.mspx
+ */
+ switch (nchannels) {
+ case 11:
+ channel_mask |= 0x00400;
+ channel_mask |= 0x00200;
+ case 9:
+ channel_mask |= 0x00100;
+ case 8:
+ channel_mask |= 0x00080;
+ channel_mask |= 0x00040;
+ case 6:
+ channel_mask |= 0x00020;
+ channel_mask |= 0x00010;
+ case 4:
+ channel_mask |= 0x00008;
+ case 3:
+ channel_mask |= 0x00004;
+ case 2:
+ channel_mask |= 0x00002;
+ channel_mask |= 0x00001;
+ break;
+ case 1:
+ /* For mono use front center */
+ channel_mask |= 0x00004;
+ break;
+ }
+
+ return channel_mask;
+}
+
+static const struct
+{
+ const guint32 ms_mask;
+ const GstAudioChannelPosition gst_pos;
+} layout_mapping[] = {
+ {
+ 0x00001, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, {
+ 0x00002, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
+ 0x00004, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
+ 0x00008, GST_AUDIO_CHANNEL_POSITION_LFE}, {
+ 0x00010, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT}, {
+ 0x00020, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
+ 0x00040, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, {
+ 0x00080, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, {
+ 0x00100, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
+ 0x00200, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT}, {
+ 0x00400, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, {
+ 0x00800, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_CENTER */
+ {
+ 0x01000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_FRONT_LEFT */
+ {
+ 0x02000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_FRONT_CENTER */
+ {
+ 0x04000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_FRONT_RIGHT */
+ {
+ 0x08000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_BACK_LEFT */
+ {
+ 0x10000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_BACK_CENTER */
+ {
+ 0x20000, GST_AUDIO_CHANNEL_POSITION_INVALID} /* TOP_BACK_RIGHT */
+};
+
+#define MAX_CHANNEL_POSITIONS G_N_ELEMENTS (layout_mapping)
+
+gboolean
+gst_wavpack_set_channel_layout (GstCaps * caps, gint layout)
+{
+ GstAudioChannelPosition pos[MAX_CHANNEL_POSITIONS];
+ GstStructure *s;
+ gint num_channels, i, p;
+
+ s = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_get_int (s, "channels", &num_channels))
+ g_return_val_if_reached (FALSE);
+
+ if (num_channels == 1 && layout == 0x00004) {
+ pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO;
+ gst_audio_set_channel_positions (s, pos);
+ return TRUE;
+ }
+
+ p = 0;
+ for (i = 0; i < MAX_CHANNEL_POSITIONS; ++i) {
+ if ((layout & layout_mapping[i].ms_mask) != 0) {
+ if (p >= num_channels) {
+ GST_WARNING ("More bits set in the channel layout map than there "
+ "are channels! Broken file");
+ return FALSE;
+ }
+ if (layout_mapping[i].gst_pos == GST_AUDIO_CHANNEL_POSITION_INVALID) {
+ GST_WARNING ("Unsupported channel position (mask 0x%08x) in channel "
+ "layout map - ignoring those channels", layout_mapping[i].ms_mask);
+ /* what to do? just ignore it and let downstream deal with a channel
+ * layout that has INVALID positions in it for now ... */
+ }
+ pos[p] = layout_mapping[i].gst_pos;
+ ++p;
+ }
+ }
+
+ if (p != num_channels) {
+ GST_WARNING ("Only %d bits set in the channel layout map, but there are "
+ "supposed to be %d channels! Broken file", p, num_channels);
+ return FALSE;
+ }
+
+ gst_audio_set_channel_positions (s, pos);
+ return TRUE;
+}
+
+GstAudioChannelPosition *
+gst_wavpack_get_default_channel_positions (gint nchannels)
+{
+ GstAudioChannelPosition *pos = g_new (GstAudioChannelPosition, nchannels);
+ gint i;
+
+ if (nchannels == 1) {
+ pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
+ return pos;
+ }
+
+ for (i = 0; i < nchannels; i++)
+ pos[i] = layout_mapping[i].gst_pos;
+
+ return pos;
+}
+
+gint
+gst_wavpack_get_channel_mask_from_positions (GstAudioChannelPosition * pos,
+ gint nchannels)
+{
+ gint channel_mask = 0;
+ gint i, j;
+
+ if (nchannels == 1 && pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) {
+ channel_mask = 0x00000004;
+ return channel_mask;
+ }
+
+ /* FIXME: not exactly efficient but otherwise we need an inverse
+ * mapping table too */
+ for (i = 0; i < nchannels; i++) {
+ for (j = 0; j < MAX_CHANNEL_POSITIONS; j++) {
+ if (pos[i] == layout_mapping[j].gst_pos) {
+ channel_mask |= layout_mapping[j].ms_mask;
+ break;
+ }
+ }
+ }
+
+ return channel_mask;
+}
+
+gboolean
+gst_wavpack_set_channel_mapping (GstAudioChannelPosition * pos, gint nchannels,
+ gint8 * channel_mapping)
+{
+ gint i, j;
+ gboolean ret = TRUE;
+
+ for (i = 0; i < nchannels; i++) {
+ for (j = 0; j < MAX_CHANNEL_POSITIONS; j++) {
+ if (pos[i] == layout_mapping[j].gst_pos) {
+ channel_mapping[i] = j;
+ ret &= (i == j);
+ break;
+ }
+ }
+ }
+
+ return !ret;
+}
diff --git a/ext/wavpack/gstwavpackcommon.h b/ext/wavpack/gstwavpackcommon.h
new file mode 100644
index 0000000..6a9e516
--- /dev/null
+++ b/ext/wavpack/gstwavpackcommon.h
@@ -0,0 +1,75 @@
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackcommon.h: common helper functions
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_WAVPACK_COMMON_H__
+#define __GST_WAVPACK_COMMON_H__
+
+#include <gst/gst.h>
+#include <gst/audio/multichannel.h>
+#include <wavpack/wavpack.h>
+
+typedef struct
+{
+ guint32 byte_length;
+ guint8 *data;
+ guint8 id;
+} GstWavpackMetadata;
+
+#define ID_UNIQUE 0x3f
+#define ID_OPTIONAL_DATA 0x20
+#define ID_ODD_SIZE 0x40
+#define ID_LARGE 0x80
+
+#define ID_DUMMY 0x0
+#define ID_ENCODER_INFO 0x1
+#define ID_DECORR_TERMS 0x2
+#define ID_DECORR_WEIGHTS 0x3
+#define ID_DECORR_SAMPLES 0x4
+#define ID_ENTROPY_VARS 0x5
+#define ID_HYBRID_PROFILE 0x6
+#define ID_SHAPING_WEIGHTS 0x7
+#define ID_FLOAT_INFO 0x8
+#define ID_INT32_INFO 0x9
+#define ID_WV_BITSTREAM 0xa
+#define ID_WVC_BITSTREAM 0xb
+#define ID_WVX_BITSTREAM 0xc
+#define ID_CHANNEL_INFO 0xd
+
+#define ID_RIFF_HEADER (ID_OPTIONAL_DATA | 0x1)
+#define ID_RIFF_TRAILER (ID_OPTIONAL_DATA | 0x2)
+#define ID_REPLAY_GAIN (ID_OPTIONAL_DATA | 0x3)
+#define ID_CUESHEET (ID_OPTIONAL_DATA | 0x4)
+#define ID_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0x5)
+#define ID_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x6)
+#define ID_SAMPLE_RATE (ID_OPTIONAL_DATA | 0x7)
+
+
+gboolean gst_wavpack_read_header (WavpackHeader * header, guint8 * buf);
+gboolean gst_wavpack_read_metadata (GstWavpackMetadata * meta,
+ guint8 * header_data, guint8 ** p_data);
+gint gst_wavpack_get_default_channel_mask (gint nchannels);
+gboolean gst_wavpack_set_channel_layout (GstCaps * caps, gint layout);
+GstAudioChannelPosition *gst_wavpack_get_default_channel_positions (gint nchannels);
+gint gst_wavpack_get_channel_mask_from_positions (GstAudioChannelPosition *pos, gint nchannels);
+gboolean gst_wavpack_set_channel_mapping (GstAudioChannelPosition *pos, gint nchannels, gint8 *channel_mapping);
+
+#endif
diff --git a/ext/wavpack/gstwavpackdec.c b/ext/wavpack/gstwavpackdec.c
new file mode 100644
index 0000000..4ba242d
--- /dev/null
+++ b/ext/wavpack/gstwavpackdec.c
@@ -0,0 +1,512 @@
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (c) 2006 Edward Hervey <bilboed@gmail.com>
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackdec.c: raw Wavpack bitstream decoder
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-wavpackdec
+ *
+ * WavpackDec decodes framed (for example by the WavpackParse element)
+ * Wavpack streams and decodes them to raw audio.
+ * <ulink url="http://www.wavpack.com/">Wavpack</ulink> is an open-source
+ * audio codec that features both lossless and lossy encoding.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch filesrc location=test.wv ! wavpackparse ! wavpackdec ! audioconvert ! audioresample ! autoaudiosink
+ * ]| This pipeline decodes the Wavpack file test.wv into raw audio buffers and
+ * tries to play it back using an automatically found audio sink.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/multichannel.h>
+
+#include <math.h>
+#include <string.h>
+
+#include <wavpack/wavpack.h>
+#include "gstwavpackdec.h"
+#include "gstwavpackcommon.h"
+#include "gstwavpackstreamreader.h"
+
+
+#define WAVPACK_DEC_MAX_ERRORS 16
+
+GST_DEBUG_CATEGORY_STATIC (gst_wavpack_dec_debug);
+#define GST_CAT_DEFAULT gst_wavpack_dec_debug
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-wavpack, "
+ "width = (int) [ 1, 32 ], "
+ "channels = (int) [ 1, 8 ], "
+ "rate = (int) [ 6000, 192000 ], " "framed = (boolean) true")
+ );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw-int, "
+ "width = (int) 32, "
+ "depth = (int) [ 1, 32 ], "
+ "channels = (int) [ 1, 8 ], "
+ "rate = (int) [ 6000, 192000 ], "
+ "endianness = (int) BYTE_ORDER, " "signed = (boolean) true")
+ );
+
+static GstFlowReturn gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_wavpack_dec_sink_set_caps (GstPad * pad, GstCaps * caps);
+static gboolean gst_wavpack_dec_sink_event (GstPad * pad, GstEvent * event);
+static void gst_wavpack_dec_finalize (GObject * object);
+static GstStateChangeReturn gst_wavpack_dec_change_state (GstElement * element,
+ GstStateChange transition);
+static void gst_wavpack_dec_post_tags (GstWavpackDec * dec);
+
+GST_BOILERPLATE (GstWavpackDec, gst_wavpack_dec, GstElement, GST_TYPE_ELEMENT);
+
+static void
+gst_wavpack_dec_base_init (gpointer klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_static_pad_template (element_class, &src_factory);
+ gst_element_class_add_static_pad_template (element_class, &sink_factory);
+ gst_element_class_set_details_simple (element_class, "Wavpack audio decoder",
+ "Codec/Decoder/Audio",
+ "Decodes Wavpack audio data",
+ "Arwed v. Merkatz <v.merkatz@gmx.net>, "
+ "Sebastian Dröge <slomo@circular-chaos.org>");
+}
+
+static void
+gst_wavpack_dec_class_init (GstWavpackDecClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_wavpack_dec_change_state);
+ gobject_class->finalize = gst_wavpack_dec_finalize;
+}
+
+static void
+gst_wavpack_dec_reset (GstWavpackDec * dec)
+{
+ dec->wv_id.buffer = NULL;
+ dec->wv_id.position = dec->wv_id.length = 0;
+
+ dec->error_count = 0;
+
+ dec->channels = 0;
+ dec->channel_mask = 0;
+ dec->sample_rate = 0;
+ dec->depth = 0;
+
+ gst_segment_init (&dec->segment, GST_FORMAT_TIME);
+ dec->next_block_index = 0;
+}
+
+static void
+gst_wavpack_dec_init (GstWavpackDec * dec, GstWavpackDecClass * gklass)
+{
+ dec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
+ gst_pad_set_chain_function (dec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_dec_chain));
+ gst_pad_set_setcaps_function (dec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_dec_sink_set_caps));
+ gst_pad_set_event_function (dec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_dec_sink_event));
+ gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
+
+ dec->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
+ gst_pad_use_fixed_caps (dec->srcpad);
+ gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
+
+ dec->context = NULL;
+ dec->stream_reader = gst_wavpack_stream_reader_new ();
+
+ gst_wavpack_dec_reset (dec);
+}
+
+static void
+gst_wavpack_dec_finalize (GObject * object)
+{
+ GstWavpackDec *dec = GST_WAVPACK_DEC (object);
+
+ g_free (dec->stream_reader);
+ dec->stream_reader = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_wavpack_dec_sink_set_caps (GstPad * pad, GstCaps * caps)
+{
+ GstWavpackDec *dec = GST_WAVPACK_DEC (gst_pad_get_parent (pad));
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+
+ /* Check if we can set the caps here already */
+ if (gst_structure_get_int (structure, "channels", &dec->channels) &&
+ gst_structure_get_int (structure, "rate", &dec->sample_rate) &&
+ gst_structure_get_int (structure, "width", &dec->depth)) {
+ GstCaps *caps;
+ GstAudioChannelPosition *pos;
+
+ caps = gst_caps_new_simple ("audio/x-raw-int",
+ "rate", G_TYPE_INT, dec->sample_rate,
+ "channels", G_TYPE_INT, dec->channels,
+ "depth", G_TYPE_INT, dec->depth,
+ "width", G_TYPE_INT, 32,
+ "endianness", G_TYPE_INT, G_BYTE_ORDER,
+ "signed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+ /* If we already have the channel layout set from upstream
+ * take this */
+ if (gst_structure_has_field (structure, "channel-positions")) {
+ pos = gst_audio_get_channel_positions (structure);
+ if (pos != NULL && dec->channels > 2) {
+ GstStructure *new_str = gst_caps_get_structure (caps, 0);
+
+ gst_audio_set_channel_positions (new_str, pos);
+ dec->channel_mask =
+ gst_wavpack_get_channel_mask_from_positions (pos, dec->channels);
+ }
+
+ if (pos != NULL)
+ g_free (pos);
+ }
+
+ GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps);
+
+ /* should always succeed */
+ gst_pad_set_caps (dec->srcpad, caps);
+ gst_caps_unref (caps);
+
+ /* send GST_TAG_AUDIO_CODEC and GST_TAG_BITRATE tags before something
+ * is decoded or after the format has changed */
+ gst_wavpack_dec_post_tags (dec);
+ }
+
+ gst_object_unref (dec);
+
+ return TRUE;
+}
+
+static void
+gst_wavpack_dec_post_tags (GstWavpackDec * dec)
+{
+ GstTagList *list;
+ GstFormat format_time = GST_FORMAT_TIME, format_bytes = GST_FORMAT_BYTES;
+ gint64 duration, size;
+
+ list = gst_tag_list_new ();
+
+ gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+ GST_TAG_AUDIO_CODEC, "Wavpack", NULL);
+
+ /* try to estimate the average bitrate */
+ if (gst_pad_query_peer_duration (dec->sinkpad, &format_bytes, &size) &&
+ gst_pad_query_peer_duration (dec->sinkpad, &format_time, &duration) &&
+ size > 0 && duration > 0) {
+ guint64 bitrate;
+
+ bitrate = gst_util_uint64_scale (size, 8 * GST_SECOND, duration);
+ gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
+ (guint) bitrate, NULL);
+ }
+
+ gst_element_post_message (GST_ELEMENT (dec),
+ gst_message_new_tag (GST_OBJECT (dec), list));
+}
+
+static GstFlowReturn
+gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstWavpackDec *dec;
+ GstBuffer *outbuf = NULL;
+ GstFlowReturn ret = GST_FLOW_OK;
+ WavpackHeader wph;
+ int32_t decoded, unpacked_size;
+ gboolean format_changed;
+
+ dec = GST_WAVPACK_DEC (GST_PAD_PARENT (pad));
+
+ /* check input, we only accept framed input with complete chunks */
+ if (GST_BUFFER_SIZE (buf) < sizeof (WavpackHeader))
+ goto input_not_framed;
+
+ if (!gst_wavpack_read_header (&wph, GST_BUFFER_DATA (buf)))
+ goto invalid_header;
+
+ if (GST_BUFFER_SIZE (buf) < wph.ckSize + 4 * 1 + 4)
+ goto input_not_framed;
+
+ if (!(wph.flags & INITIAL_BLOCK))
+ goto input_not_framed;
+
+ dec->wv_id.buffer = GST_BUFFER_DATA (buf);
+ dec->wv_id.length = GST_BUFFER_SIZE (buf);
+ dec->wv_id.position = 0;
+
+ /* create a new wavpack context if there is none yet but if there
+ * was already one (i.e. caps were set on the srcpad) check whether
+ * the new one has the same caps */
+ if (!dec->context) {
+ gchar error_msg[80];
+
+ dec->context = WavpackOpenFileInputEx (dec->stream_reader,
+ &dec->wv_id, NULL, error_msg, OPEN_STREAMING, 0);
+
+ if (!dec->context) {
+ GST_WARNING ("Couldn't decode buffer: %s", error_msg);
+ dec->error_count++;
+ if (dec->error_count <= WAVPACK_DEC_MAX_ERRORS) {
+ goto out; /* just return OK for now */
+ } else {
+ goto decode_error;
+ }
+ }
+ }
+
+ g_assert (dec->context != NULL);
+
+ dec->error_count = 0;
+
+ format_changed =
+ (dec->sample_rate != WavpackGetSampleRate (dec->context)) ||
+ (dec->channels != WavpackGetNumChannels (dec->context)) ||
+ (dec->depth != WavpackGetBitsPerSample (dec->context)) ||
+#ifdef WAVPACK_OLD_API
+ (dec->channel_mask != dec->context->config.channel_mask);
+#else
+ (dec->channel_mask != WavpackGetChannelMask (dec->context));
+#endif
+
+ if (!GST_PAD_CAPS (dec->srcpad) || format_changed) {
+ GstCaps *caps;
+ gint channel_mask;
+
+ dec->sample_rate = WavpackGetSampleRate (dec->context);
+ dec->channels = WavpackGetNumChannels (dec->context);
+ dec->depth = WavpackGetBitsPerSample (dec->context);
+
+ caps = gst_caps_new_simple ("audio/x-raw-int",
+ "rate", G_TYPE_INT, dec->sample_rate,
+ "channels", G_TYPE_INT, dec->channels,
+ "depth", G_TYPE_INT, dec->depth,
+ "width", G_TYPE_INT, 32,
+ "endianness", G_TYPE_INT, G_BYTE_ORDER,
+ "signed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+#ifdef WAVPACK_OLD_API
+ channel_mask = dec->context->config.channel_mask;
+#else
+ channel_mask = WavpackGetChannelMask (dec->context);
+#endif
+ if (channel_mask == 0)
+ channel_mask = gst_wavpack_get_default_channel_mask (dec->channels);
+
+ dec->channel_mask = channel_mask;
+
+ /* Only set the channel layout for more than two channels
+ * otherwise things break unfortunately */
+ if (channel_mask != 0 && dec->channels > 2)
+ if (!gst_wavpack_set_channel_layout (caps, channel_mask))
+ GST_WARNING_OBJECT (dec, "Failed to set channel layout");
+
+ GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps);
+
+ /* should always succeed */
+ gst_pad_set_caps (dec->srcpad, caps);
+ gst_caps_unref (caps);
+
+ /* send GST_TAG_AUDIO_CODEC and GST_TAG_BITRATE tags before something
+ * is decoded or after the format has changed */
+ gst_wavpack_dec_post_tags (dec);
+ }
+
+ /* alloc output buffer */
+ unpacked_size = 4 * wph.block_samples * dec->channels;
+ ret = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET (buf),
+ unpacked_size, GST_PAD_CAPS (dec->srcpad), &outbuf);
+
+ if (ret != GST_FLOW_OK)
+ goto out;
+
+ gst_buffer_copy_metadata (outbuf, buf, GST_BUFFER_COPY_TIMESTAMPS);
+
+ /* If we got a DISCONT buffer forward the flag. Nothing else
+ * has to be done as libwavpack doesn't store state between
+ * Wavpack blocks */
+ if (GST_BUFFER_IS_DISCONT (buf) || dec->next_block_index != wph.block_index)
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+
+ dec->next_block_index = wph.block_index + wph.block_samples;
+
+ /* decode */
+ decoded = WavpackUnpackSamples (dec->context,
+ (int32_t *) GST_BUFFER_DATA (outbuf), wph.block_samples);
+ if (decoded != wph.block_samples)
+ goto decode_error;
+
+ if ((outbuf = gst_audio_buffer_clip (outbuf, &dec->segment,
+ dec->sample_rate, 4 * dec->channels))) {
+ GST_LOG_OBJECT (dec, "pushing buffer with time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
+ ret = gst_pad_push (dec->srcpad, outbuf);
+ }
+
+out:
+
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (ret));
+ }
+
+ gst_buffer_unref (buf);
+
+ return ret;
+
+/* ERRORS */
+input_not_framed:
+ {
+ GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Expected framed input"));
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
+ }
+invalid_header:
+ {
+ GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Invalid wavpack header"));
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
+ }
+decode_error:
+ {
+ const gchar *reason = "unknown";
+
+ if (dec->context) {
+#ifdef WAVPACK_OLD_API
+ reason = dec->context->error_message;
+#else
+ reason = WavpackGetErrorMessage (dec->context);
+#endif
+ } else {
+ reason = "couldn't create decoder context";
+ }
+ GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
+ ("Failed to decode wavpack stream: %s", reason));
+ if (outbuf)
+ gst_buffer_unref (outbuf);
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
+ }
+}
+
+static gboolean
+gst_wavpack_dec_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstWavpackDec *dec = GST_WAVPACK_DEC (gst_pad_get_parent (pad));
+
+ GST_LOG_OBJECT (dec, "Received %s event", GST_EVENT_TYPE_NAME (event));
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_NEWSEGMENT:{
+ GstFormat fmt;
+ gboolean is_update;
+ gint64 start, end, base;
+ gdouble rate;
+
+ gst_event_parse_new_segment (event, &is_update, &rate, &fmt, &start,
+ &end, &base);
+ if (fmt == GST_FORMAT_TIME) {
+ GST_DEBUG ("Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
+ GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
+ GST_TIME_ARGS (end));
+ gst_segment_set_newsegment (&dec->segment, is_update, rate, fmt,
+ start, end, base);
+ } else {
+ gst_segment_init (&dec->segment, GST_FORMAT_TIME);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ gst_object_unref (dec);
+ return gst_pad_event_default (pad, event);
+}
+
+static GstStateChangeReturn
+gst_wavpack_dec_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstWavpackDec *dec = GST_WAVPACK_DEC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ if (dec->context) {
+ WavpackCloseFile (dec->context);
+ dec->context = NULL;
+ }
+
+ gst_wavpack_dec_reset (dec);
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+gboolean
+gst_wavpack_dec_plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "wavpackdec",
+ GST_RANK_PRIMARY, GST_TYPE_WAVPACK_DEC))
+ return FALSE;
+ GST_DEBUG_CATEGORY_INIT (gst_wavpack_dec_debug, "wavpack_dec", 0,
+ "Wavpack decoder");
+ return TRUE;
+}
diff --git a/ext/wavpack/gstwavpackdec.h b/ext/wavpack/gstwavpackdec.h
new file mode 100644
index 0000000..eb6e4c3
--- /dev/null
+++ b/ext/wavpack/gstwavpackdec.h
@@ -0,0 +1,80 @@
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2004 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackdec.h: raw Wavpack bitstream decoder
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_WAVPACK_DEC_H__
+#define __GST_WAVPACK_DEC_H__
+
+#include <gst/gst.h>
+
+#include <wavpack/wavpack.h>
+
+#include "gstwavpackstreamreader.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_WAVPACK_DEC \
+ (gst_wavpack_dec_get_type())
+#define GST_WAVPACK_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVPACK_DEC,GstWavpackDec))
+#define GST_WAVPACK_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVPACK_DEC,GstWavpackDecClass))
+#define GST_IS_WAVPACK_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVPACK_DEC))
+#define GST_IS_WAVPACK_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVPACK_DEC))
+typedef struct _GstWavpackDec GstWavpackDec;
+typedef struct _GstWavpackDecClass GstWavpackDecClass;
+
+struct _GstWavpackDec
+{
+ GstElement element;
+
+ /*< private > */
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ WavpackContext *context;
+ WavpackStreamReader *stream_reader;
+
+ read_id wv_id;
+
+ GstSegment segment; /* used for clipping, TIME format */
+ guint32 next_block_index;
+
+ gint sample_rate;
+ gint depth;
+ gint channels;
+ gint channel_mask;
+
+ gint error_count;
+};
+
+struct _GstWavpackDecClass
+{
+ GstElementClass parent;
+};
+
+GType gst_wavpack_dec_get_type (void);
+
+gboolean gst_wavpack_dec_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_WAVPACK_DEC_H__ */
diff --git a/ext/wavpack/gstwavpackenc.c b/ext/wavpack/gstwavpackenc.c
new file mode 100644
index 0000000..a22dd23
--- /dev/null
+++ b/ext/wavpack/gstwavpackenc.c
@@ -0,0 +1,1049 @@
+/* GStreamer Wavpack encoder plugin
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackdec.c: Wavpack audio encoder
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-wavpackenc
+ *
+ * WavpackEnc encodes raw audio into a framed Wavpack stream.
+ * <ulink url="http://www.wavpack.com/">Wavpack</ulink> is an open-source
+ * audio codec that features both lossless and lossy encoding.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch audiotestsrc num-buffers=500 ! audioconvert ! wavpackenc ! filesink location=sinewave.wv
+ * ]| This pipeline encodes audio from audiotestsrc into a Wavpack file. The audioconvert element is needed
+ * as the Wavpack encoder only accepts input with 32 bit width (and every depth between 1 and 32 bits).
+ * |[
+ * gst-launch cdda://1 ! audioconvert ! wavpackenc ! filesink location=track1.wv
+ * ]| This pipeline encodes audio from an audio CD into a Wavpack file using
+ * lossless encoding (the file output will be fairly large).
+ * |[
+ * gst-launch cdda://1 ! audioconvert ! wavpackenc bitrate=128000 ! filesink location=track1.wv
+ * ]| This pipeline encodes audio from an audio CD into a Wavpack file using
+ * lossy encoding at a certain bitrate (the file will be fairly small).
+ * </refsect2>
+ */
+
+/*
+ * TODO: - add 32 bit float mode. CONFIG_FLOAT_DATA
+ */
+
+#include <string.h>
+#include <gst/gst.h>
+#include <glib/gprintf.h>
+
+#include <wavpack/wavpack.h>
+#include "gstwavpackenc.h"
+#include "gstwavpackcommon.h"
+
+static GstFlowReturn gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_wavpack_enc_sink_set_caps (GstPad * pad, GstCaps * caps);
+static int gst_wavpack_enc_push_block (void *id, void *data, int32_t count);
+static gboolean gst_wavpack_enc_sink_event (GstPad * pad, GstEvent * event);
+static GstStateChangeReturn gst_wavpack_enc_change_state (GstElement * element,
+ GstStateChange transition);
+static void gst_wavpack_enc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_wavpack_enc_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+enum
+{
+ ARG_0,
+ ARG_MODE,
+ ARG_BITRATE,
+ ARG_BITSPERSAMPLE,
+ ARG_CORRECTION_MODE,
+ ARG_MD5,
+ ARG_EXTRA_PROCESSING,
+ ARG_JOINT_STEREO_MODE
+};
+
+GST_DEBUG_CATEGORY_STATIC (gst_wavpack_enc_debug);
+#define GST_CAT_DEFAULT gst_wavpack_enc_debug
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw-int, "
+ "width = (int) 32, "
+ "depth = (int) [ 1, 32], "
+ "endianness = (int) BYTE_ORDER, "
+ "channels = (int) [ 1, 8 ], "
+ "rate = (int) [ 6000, 192000 ]," "signed = (boolean) TRUE")
+ );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-wavpack, "
+ "width = (int) [ 1, 32 ], "
+ "channels = (int) [ 1, 2 ], "
+ "rate = (int) [ 6000, 192000 ], " "framed = (boolean) TRUE")
+ );
+
+static GstStaticPadTemplate wvcsrc_factory = GST_STATIC_PAD_TEMPLATE ("wvcsrc",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS ("audio/x-wavpack-correction, " "framed = (boolean) TRUE")
+ );
+
+enum
+{
+ GST_WAVPACK_ENC_MODE_VERY_FAST = 0,
+ GST_WAVPACK_ENC_MODE_FAST,
+ GST_WAVPACK_ENC_MODE_DEFAULT,
+ GST_WAVPACK_ENC_MODE_HIGH,
+ GST_WAVPACK_ENC_MODE_VERY_HIGH
+};
+
+#define GST_TYPE_WAVPACK_ENC_MODE (gst_wavpack_enc_mode_get_type ())
+static GType
+gst_wavpack_enc_mode_get_type (void)
+{
+ static GType qtype = 0;
+
+ if (qtype == 0) {
+ static const GEnumValue values[] = {
+#if 0
+ /* Very Fast Compression is not supported yet, but will be supported
+ * in future wavpack versions */
+ {GST_WAVPACK_ENC_MODE_VERY_FAST, "Very Fast Compression", "veryfast"},
+#endif
+ {GST_WAVPACK_ENC_MODE_FAST, "Fast Compression", "fast"},
+ {GST_WAVPACK_ENC_MODE_DEFAULT, "Normal Compression", "normal"},
+ {GST_WAVPACK_ENC_MODE_HIGH, "High Compression", "high"},
+#ifndef WAVPACK_OLD_API
+ {GST_WAVPACK_ENC_MODE_VERY_HIGH, "Very High Compression", "veryhigh"},
+#endif
+ {0, NULL, NULL}
+ };
+
+ qtype = g_enum_register_static ("GstWavpackEncMode", values);
+ }
+ return qtype;
+}
+
+enum
+{
+ GST_WAVPACK_CORRECTION_MODE_OFF = 0,
+ GST_WAVPACK_CORRECTION_MODE_ON,
+ GST_WAVPACK_CORRECTION_MODE_OPTIMIZED
+};
+
+#define GST_TYPE_WAVPACK_ENC_CORRECTION_MODE (gst_wavpack_enc_correction_mode_get_type ())
+static GType
+gst_wavpack_enc_correction_mode_get_type (void)
+{
+ static GType qtype = 0;
+
+ if (qtype == 0) {
+ static const GEnumValue values[] = {
+ {GST_WAVPACK_CORRECTION_MODE_OFF, "Create no correction file", "off"},
+ {GST_WAVPACK_CORRECTION_MODE_ON, "Create correction file", "on"},
+ {GST_WAVPACK_CORRECTION_MODE_OPTIMIZED,
+ "Create optimized correction file", "optimized"},
+ {0, NULL, NULL}
+ };
+
+ qtype = g_enum_register_static ("GstWavpackEncCorrectionMode", values);
+ }
+ return qtype;
+}
+
+enum
+{
+ GST_WAVPACK_JS_MODE_AUTO = 0,
+ GST_WAVPACK_JS_MODE_LEFT_RIGHT,
+ GST_WAVPACK_JS_MODE_MID_SIDE
+};
+
+#define GST_TYPE_WAVPACK_ENC_JOINT_STEREO_MODE (gst_wavpack_enc_joint_stereo_mode_get_type ())
+static GType
+gst_wavpack_enc_joint_stereo_mode_get_type (void)
+{
+ static GType qtype = 0;
+
+ if (qtype == 0) {
+ static const GEnumValue values[] = {
+ {GST_WAVPACK_JS_MODE_AUTO, "auto", "auto"},
+ {GST_WAVPACK_JS_MODE_LEFT_RIGHT, "left/right", "leftright"},
+ {GST_WAVPACK_JS_MODE_MID_SIDE, "mid/side", "midside"},
+ {0, NULL, NULL}
+ };
+
+ qtype = g_enum_register_static ("GstWavpackEncJSMode", values);
+ }
+ return qtype;
+}
+
+static void
+_do_init (GType object_type)
+{
+ const GInterfaceInfo preset_interface_info = {
+ NULL, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+
+ g_type_add_interface_static (object_type, GST_TYPE_PRESET,
+ &preset_interface_info);
+}
+
+GST_BOILERPLATE_FULL (GstWavpackEnc, gst_wavpack_enc, GstElement,
+ GST_TYPE_ELEMENT, _do_init);
+
+static void
+gst_wavpack_enc_base_init (gpointer klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ /* add pad templates */
+ gst_element_class_add_static_pad_template (element_class, &sink_factory);
+ gst_element_class_add_static_pad_template (element_class, &src_factory);
+ gst_element_class_add_static_pad_template (element_class,
+ &wvcsrc_factory);
+
+ /* set element details */
+ gst_element_class_set_details_simple (element_class, "Wavpack audio encoder",
+ "Codec/Encoder/Audio",
+ "Encodes audio with the Wavpack lossless/lossy audio codec",
+ "Sebastian Dröge <slomo@circular-chaos.org>");
+}
+
+
+static void
+gst_wavpack_enc_class_init (GstWavpackEncClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ /* set state change handler */
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_wavpack_enc_change_state);
+
+ /* set property handlers */
+ gobject_class->set_property = gst_wavpack_enc_set_property;
+ gobject_class->get_property = gst_wavpack_enc_get_property;
+
+ /* install all properties */
+ g_object_class_install_property (gobject_class, ARG_MODE,
+ g_param_spec_enum ("mode", "Encoding mode",
+ "Speed versus compression tradeoff.",
+ GST_TYPE_WAVPACK_ENC_MODE, GST_WAVPACK_ENC_MODE_DEFAULT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, ARG_BITRATE,
+ g_param_spec_uint ("bitrate", "Bitrate",
+ "Try to encode with this average bitrate (bits/sec). "
+ "This enables lossy encoding, values smaller than 24000 disable it again.",
+ 0, 9600000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, ARG_BITSPERSAMPLE,
+ g_param_spec_double ("bits-per-sample", "Bits per sample",
+ "Try to encode with this amount of bits per sample. "
+ "This enables lossy encoding, values smaller than 2.0 disable it again.",
+ 0.0, 24.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, ARG_CORRECTION_MODE,
+ g_param_spec_enum ("correction-mode", "Correction stream mode",
+ "Use this mode for the correction stream. Only works in lossy mode!",
+ GST_TYPE_WAVPACK_ENC_CORRECTION_MODE, GST_WAVPACK_CORRECTION_MODE_OFF,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, ARG_MD5,
+ g_param_spec_boolean ("md5", "MD5",
+ "Store MD5 hash of raw samples within the file.", FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, ARG_EXTRA_PROCESSING,
+ g_param_spec_uint ("extra-processing", "Extra processing",
+ "Use better but slower filters for better compression/quality.",
+ 0, 6, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, ARG_JOINT_STEREO_MODE,
+ g_param_spec_enum ("joint-stereo-mode", "Joint-Stereo mode",
+ "Use this joint-stereo mode.", GST_TYPE_WAVPACK_ENC_JOINT_STEREO_MODE,
+ GST_WAVPACK_JS_MODE_AUTO,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_wavpack_enc_reset (GstWavpackEnc * enc)
+{
+ /* close and free everything stream related if we already did something */
+ if (enc->wp_context) {
+ WavpackCloseFile (enc->wp_context);
+ enc->wp_context = NULL;
+ }
+ if (enc->wp_config) {
+ g_free (enc->wp_config);
+ enc->wp_config = NULL;
+ }
+ if (enc->first_block) {
+ g_free (enc->first_block);
+ enc->first_block = NULL;
+ }
+ enc->first_block_size = 0;
+ if (enc->md5_context) {
+ g_checksum_free (enc->md5_context);
+ enc->md5_context = NULL;
+ }
+
+ if (enc->pending_buffer) {
+ gst_buffer_unref (enc->pending_buffer);
+ enc->pending_buffer = NULL;
+ enc->pending_offset = 0;
+ }
+
+ /* reset the last returns to GST_FLOW_OK. This is only set to something else
+ * while WavpackPackSamples() or more specific gst_wavpack_enc_push_block()
+ * so not valid anymore */
+ enc->srcpad_last_return = enc->wvcsrcpad_last_return = GST_FLOW_OK;
+
+ /* reset stream information */
+ enc->samplerate = 0;
+ enc->depth = 0;
+ enc->channels = 0;
+ enc->channel_mask = 0;
+ enc->need_channel_remap = FALSE;
+
+ enc->timestamp_offset = GST_CLOCK_TIME_NONE;
+ enc->next_ts = GST_CLOCK_TIME_NONE;
+}
+
+static void
+gst_wavpack_enc_init (GstWavpackEnc * enc, GstWavpackEncClass * gclass)
+{
+ enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
+ gst_pad_set_setcaps_function (enc->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_enc_sink_set_caps));
+ gst_pad_set_chain_function (enc->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_enc_chain));
+ gst_pad_set_event_function (enc->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_enc_sink_event));
+ gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
+
+ /* setup src pad */
+ enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
+ gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
+
+ /* initialize object attributes */
+ enc->wp_config = NULL;
+ enc->wp_context = NULL;
+ enc->first_block = NULL;
+ enc->md5_context = NULL;
+ gst_wavpack_enc_reset (enc);
+
+ enc->wv_id.correction = FALSE;
+ enc->wv_id.wavpack_enc = enc;
+ enc->wv_id.passthrough = FALSE;
+ enc->wvc_id.correction = TRUE;
+ enc->wvc_id.wavpack_enc = enc;
+ enc->wvc_id.passthrough = FALSE;
+
+ /* set default values of params */
+ enc->mode = GST_WAVPACK_ENC_MODE_DEFAULT;
+ enc->bitrate = 0;
+ enc->bps = 0.0;
+ enc->correction_mode = GST_WAVPACK_CORRECTION_MODE_OFF;
+ enc->md5 = FALSE;
+ enc->extra_processing = 0;
+ enc->joint_stereo_mode = GST_WAVPACK_JS_MODE_AUTO;
+}
+
+static gboolean
+gst_wavpack_enc_sink_set_caps (GstPad * pad, GstCaps * caps)
+{
+ GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad));
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+ GstAudioChannelPosition *pos;
+
+ if (!gst_structure_get_int (structure, "channels", &enc->channels) ||
+ !gst_structure_get_int (structure, "rate", &enc->samplerate) ||
+ !gst_structure_get_int (structure, "depth", &enc->depth)) {
+ GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
+ ("got invalid caps: %" GST_PTR_FORMAT, caps));
+ gst_object_unref (enc);
+ return FALSE;
+ }
+
+ pos = gst_audio_get_channel_positions (structure);
+ /* If one channel is NONE they'll be all undefined */
+ if (pos != NULL && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) {
+ g_free (pos);
+ pos = NULL;
+ }
+
+ if (pos == NULL) {
+ GST_ELEMENT_ERROR (enc, STREAM, FORMAT, (NULL),
+ ("input has no valid channel layout"));
+
+ gst_object_unref (enc);
+ return FALSE;
+ }
+
+ enc->channel_mask =
+ gst_wavpack_get_channel_mask_from_positions (pos, enc->channels);
+ enc->need_channel_remap =
+ gst_wavpack_set_channel_mapping (pos, enc->channels,
+ enc->channel_mapping);
+ g_free (pos);
+
+ /* set fixed src pad caps now that we know what we will get */
+ caps = gst_caps_new_simple ("audio/x-wavpack",
+ "channels", G_TYPE_INT, enc->channels,
+ "rate", G_TYPE_INT, enc->samplerate,
+ "width", G_TYPE_INT, enc->depth, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+ if (!gst_wavpack_set_channel_layout (caps, enc->channel_mask))
+ GST_WARNING_OBJECT (enc, "setting channel layout failed");
+
+ if (!gst_pad_set_caps (enc->srcpad, caps)) {
+ GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
+ ("setting caps failed: %" GST_PTR_FORMAT, caps));
+ gst_caps_unref (caps);
+ gst_object_unref (enc);
+ return FALSE;
+ }
+ gst_pad_use_fixed_caps (enc->srcpad);
+
+ gst_caps_unref (caps);
+ gst_object_unref (enc);
+ return TRUE;
+}
+
+static void
+gst_wavpack_enc_set_wp_config (GstWavpackEnc * enc)
+{
+ enc->wp_config = g_new0 (WavpackConfig, 1);
+ /* set general stream informations in the WavpackConfig */
+ enc->wp_config->bytes_per_sample = GST_ROUND_UP_8 (enc->depth) / 8;
+ enc->wp_config->bits_per_sample = enc->depth;
+ enc->wp_config->num_channels = enc->channels;
+ enc->wp_config->channel_mask = enc->channel_mask;
+ enc->wp_config->sample_rate = enc->samplerate;
+
+ /*
+ * Set parameters in WavpackConfig
+ */
+
+ /* Encoding mode */
+ switch (enc->mode) {
+#if 0
+ case GST_WAVPACK_ENC_MODE_VERY_FAST:
+ enc->wp_config->flags |= CONFIG_VERY_FAST_FLAG;
+ enc->wp_config->flags |= CONFIG_FAST_FLAG;
+ break;
+#endif
+ case GST_WAVPACK_ENC_MODE_FAST:
+ enc->wp_config->flags |= CONFIG_FAST_FLAG;
+ break;
+ case GST_WAVPACK_ENC_MODE_DEFAULT:
+ break;
+ case GST_WAVPACK_ENC_MODE_HIGH:
+ enc->wp_config->flags |= CONFIG_HIGH_FLAG;
+ break;
+#ifndef WAVPACK_OLD_API
+ case GST_WAVPACK_ENC_MODE_VERY_HIGH:
+ enc->wp_config->flags |= CONFIG_HIGH_FLAG;
+ enc->wp_config->flags |= CONFIG_VERY_HIGH_FLAG;
+ break;
+#endif
+ }
+
+ /* Bitrate, enables lossy mode */
+ if (enc->bitrate) {
+ enc->wp_config->flags |= CONFIG_HYBRID_FLAG;
+ enc->wp_config->flags |= CONFIG_BITRATE_KBPS;
+ enc->wp_config->bitrate = enc->bitrate / 1000.0;
+ } else if (enc->bps) {
+ enc->wp_config->flags |= CONFIG_HYBRID_FLAG;
+ enc->wp_config->bitrate = enc->bps;
+ }
+
+ /* Correction Mode, only in lossy mode */
+ if (enc->wp_config->flags & CONFIG_HYBRID_FLAG) {
+ if (enc->correction_mode > GST_WAVPACK_CORRECTION_MODE_OFF) {
+ GstCaps *caps = gst_caps_new_simple ("audio/x-wavpack-correction",
+ "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+ enc->wvcsrcpad =
+ gst_pad_new_from_static_template (&wvcsrc_factory, "wvcsrc");
+
+ /* try to add correction src pad, don't set correction mode on failure */
+ GST_DEBUG_OBJECT (enc, "Adding correction pad with caps %"
+ GST_PTR_FORMAT, caps);
+ if (!gst_pad_set_caps (enc->wvcsrcpad, caps)) {
+ enc->correction_mode = 0;
+ GST_WARNING_OBJECT (enc, "setting correction caps failed");
+ } else {
+ gst_pad_use_fixed_caps (enc->wvcsrcpad);
+ gst_pad_set_active (enc->wvcsrcpad, TRUE);
+ gst_element_add_pad (GST_ELEMENT (enc), enc->wvcsrcpad);
+ enc->wp_config->flags |= CONFIG_CREATE_WVC;
+ if (enc->correction_mode == GST_WAVPACK_CORRECTION_MODE_OPTIMIZED) {
+ enc->wp_config->flags |= CONFIG_OPTIMIZE_WVC;
+ }
+ }
+ gst_caps_unref (caps);
+ }
+ } else {
+ if (enc->correction_mode > GST_WAVPACK_CORRECTION_MODE_OFF) {
+ enc->correction_mode = 0;
+ GST_WARNING_OBJECT (enc, "setting correction mode only has "
+ "any effect if a bitrate is provided.");
+ }
+ }
+ gst_element_no_more_pads (GST_ELEMENT (enc));
+
+ /* MD5, setup MD5 context */
+ if ((enc->md5) && !(enc->md5_context)) {
+ enc->wp_config->flags |= CONFIG_MD5_CHECKSUM;
+ enc->md5_context = g_checksum_new (G_CHECKSUM_MD5);
+ }
+
+ /* Extra encode processing */
+ if (enc->extra_processing) {
+ enc->wp_config->flags |= CONFIG_EXTRA_MODE;
+ enc->wp_config->xmode = enc->extra_processing;
+ }
+
+ /* Joint stereo mode */
+ switch (enc->joint_stereo_mode) {
+ case GST_WAVPACK_JS_MODE_AUTO:
+ break;
+ case GST_WAVPACK_JS_MODE_LEFT_RIGHT:
+ enc->wp_config->flags |= CONFIG_JOINT_OVERRIDE;
+ enc->wp_config->flags &= ~CONFIG_JOINT_STEREO;
+ break;
+ case GST_WAVPACK_JS_MODE_MID_SIDE:
+ enc->wp_config->flags |= (CONFIG_JOINT_OVERRIDE | CONFIG_JOINT_STEREO);
+ break;
+ }
+}
+
+static int
+gst_wavpack_enc_push_block (void *id, void *data, int32_t count)
+{
+ GstWavpackEncWriteID *wid = (GstWavpackEncWriteID *) id;
+ GstWavpackEnc *enc = GST_WAVPACK_ENC (wid->wavpack_enc);
+ GstFlowReturn *flow;
+ GstBuffer *buffer;
+ GstPad *pad;
+ guchar *block = (guchar *) data;
+
+ pad = (wid->correction) ? enc->wvcsrcpad : enc->srcpad;
+ flow =
+ (wid->correction) ? &enc->wvcsrcpad_last_return : &enc->
+ srcpad_last_return;
+
+ *flow = gst_pad_alloc_buffer_and_set_caps (pad, GST_BUFFER_OFFSET_NONE,
+ count, GST_PAD_CAPS (pad), &buffer);
+
+ if (*flow != GST_FLOW_OK) {
+ GST_WARNING_OBJECT (enc, "flow on %s:%s = %s",
+ GST_DEBUG_PAD_NAME (pad), gst_flow_get_name (*flow));
+ return FALSE;
+ }
+
+ g_memmove (GST_BUFFER_DATA (buffer), block, count);
+
+ if (count > sizeof (WavpackHeader) && memcmp (block, "wvpk", 4) == 0) {
+ /* if it's a Wavpack block set buffer timestamp and duration, etc */
+ WavpackHeader wph;
+
+ GST_LOG_OBJECT (enc, "got %d bytes of encoded wavpack %sdata",
+ count, (wid->correction) ? "correction " : "");
+
+ gst_wavpack_read_header (&wph, block);
+
+ /* Only set when pushing the first buffer again, in that case
+ * we don't want to delay the buffer or push newsegment events
+ */
+ if (!wid->passthrough) {
+ /* Only push complete blocks */
+ if (enc->pending_buffer == NULL) {
+ enc->pending_buffer = buffer;
+ enc->pending_offset = wph.block_index;
+ } else if (enc->pending_offset == wph.block_index) {
+ enc->pending_buffer = gst_buffer_join (enc->pending_buffer, buffer);
+ } else {
+ GST_ERROR ("Got incomplete block, dropping");
+ gst_buffer_unref (enc->pending_buffer);
+ enc->pending_buffer = buffer;
+ enc->pending_offset = wph.block_index;
+ }
+
+ if (!(wph.flags & FINAL_BLOCK))
+ return TRUE;
+
+ buffer = enc->pending_buffer;
+ enc->pending_buffer = NULL;
+ enc->pending_offset = 0;
+
+ /* if it's the first wavpack block, send a NEW_SEGMENT event */
+ if (wph.block_index == 0) {
+ gst_pad_push_event (pad,
+ gst_event_new_new_segment (FALSE,
+ 1.0, GST_FORMAT_TIME, 0, GST_BUFFER_OFFSET_NONE, 0));
+
+ /* save header for later reference, so we can re-send it later on
+ * EOS with fixed up values for total sample count etc. */
+ if (enc->first_block == NULL && !wid->correction) {
+ enc->first_block =
+ g_memdup (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
+ enc->first_block_size = GST_BUFFER_SIZE (buffer);
+ }
+ }
+ }
+
+ /* set buffer timestamp, duration, offset, offset_end from
+ * the wavpack header */
+ GST_BUFFER_TIMESTAMP (buffer) = enc->timestamp_offset +
+ gst_util_uint64_scale_int (GST_SECOND, wph.block_index,
+ enc->samplerate);
+ GST_BUFFER_DURATION (buffer) =
+ gst_util_uint64_scale_int (GST_SECOND, wph.block_samples,
+ enc->samplerate);
+ GST_BUFFER_OFFSET (buffer) = wph.block_index;
+ GST_BUFFER_OFFSET_END (buffer) = wph.block_index + wph.block_samples;
+ } else {
+ /* if it's something else set no timestamp and duration on the buffer */
+ GST_DEBUG_OBJECT (enc, "got %d bytes of unknown data", count);
+
+ GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
+ GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
+ }
+
+ /* push the buffer and forward errors */
+ GST_DEBUG_OBJECT (enc, "pushing buffer with %d bytes",
+ GST_BUFFER_SIZE (buffer));
+ *flow = gst_pad_push (pad, buffer);
+
+ if (*flow != GST_FLOW_OK) {
+ GST_WARNING_OBJECT (enc, "flow on %s:%s = %s",
+ GST_DEBUG_PAD_NAME (pad), gst_flow_get_name (*flow));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+gst_wavpack_enc_fix_channel_order (GstWavpackEnc * enc, gint32 * data,
+ gint nsamples)
+{
+ gint i, j;
+ gint32 tmp[8];
+
+ for (i = 0; i < nsamples / enc->channels; i++) {
+ for (j = 0; j < enc->channels; j++) {
+ tmp[enc->channel_mapping[j]] = data[j];
+ }
+ for (j = 0; j < enc->channels; j++) {
+ data[j] = tmp[j];
+ }
+ data += enc->channels;
+ }
+}
+
+static GstFlowReturn
+gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad));
+ uint32_t sample_count = GST_BUFFER_SIZE (buf) / 4;
+ GstFlowReturn ret;
+
+ /* reset the last returns to GST_FLOW_OK. This is only set to something else
+ * while WavpackPackSamples() or more specific gst_wavpack_enc_push_block()
+ * so not valid anymore */
+ enc->srcpad_last_return = enc->wvcsrcpad_last_return = GST_FLOW_OK;
+
+ GST_DEBUG ("got %u raw samples", sample_count);
+
+ /* check if we already have a valid WavpackContext, otherwise make one */
+ if (!enc->wp_context) {
+ /* create raw context */
+ enc->wp_context =
+ WavpackOpenFileOutput (gst_wavpack_enc_push_block, &enc->wv_id,
+ (enc->correction_mode > 0) ? &enc->wvc_id : NULL);
+ if (!enc->wp_context) {
+ GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
+ ("error creating Wavpack context"));
+ gst_object_unref (enc);
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
+ }
+
+ /* set the WavpackConfig according to our parameters */
+ gst_wavpack_enc_set_wp_config (enc);
+
+ /* set the configuration to the context now that we know everything
+ * and initialize the encoder */
+ if (!WavpackSetConfiguration (enc->wp_context,
+ enc->wp_config, (uint32_t) (-1))
+ || !WavpackPackInit (enc->wp_context)) {
+ GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL),
+ ("error setting up wavpack encoding context"));
+ WavpackCloseFile (enc->wp_context);
+ gst_object_unref (enc);
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
+ }
+ GST_DEBUG ("setup of encoding context successfull");
+ }
+
+ /* Save the timestamp of the first buffer. This will be later
+ * used as offset for all following buffers */
+ if (enc->timestamp_offset == GST_CLOCK_TIME_NONE) {
+ if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+ enc->timestamp_offset = GST_BUFFER_TIMESTAMP (buf);
+ enc->next_ts = GST_BUFFER_TIMESTAMP (buf);
+ } else {
+ enc->timestamp_offset = 0;
+ enc->next_ts = 0;
+ }
+ }
+
+ /* Check if we have a continous stream, if not drop some samples or the buffer or
+ * insert some silence samples */
+ if (enc->next_ts != GST_CLOCK_TIME_NONE &&
+ GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) {
+ guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf);
+ guint64 diff_bytes;
+
+ GST_WARNING_OBJECT (enc, "Buffer is older than previous "
+ "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
+ "), cannot handle. Clipping buffer.",
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
+ GST_TIME_ARGS (enc->next_ts));
+
+ diff_bytes =
+ GST_CLOCK_TIME_TO_FRAMES (diff, enc->samplerate) * enc->channels * 2;
+ if (diff_bytes >= GST_BUFFER_SIZE (buf)) {
+ gst_buffer_unref (buf);
+ return GST_FLOW_OK;
+ }
+ buf = gst_buffer_make_metadata_writable (buf);
+ GST_BUFFER_DATA (buf) += diff_bytes;
+ GST_BUFFER_SIZE (buf) -= diff_bytes;
+
+ GST_BUFFER_TIMESTAMP (buf) += diff;
+ if (GST_BUFFER_DURATION_IS_VALID (buf))
+ GST_BUFFER_DURATION (buf) -= diff;
+ }
+
+ /* Allow a diff of at most 5 ms */
+ if (enc->next_ts != GST_CLOCK_TIME_NONE
+ && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+ if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts &&
+ GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > 5 * GST_MSECOND) {
+ GST_WARNING_OBJECT (enc,
+ "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT,
+ GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, 5 * GST_MSECOND);
+
+ WavpackFlushSamples (enc->wp_context);
+ enc->timestamp_offset += (GST_BUFFER_TIMESTAMP (buf) - enc->next_ts);
+ }
+ }
+
+ if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)
+ && GST_BUFFER_DURATION_IS_VALID (buf))
+ enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
+ else
+ enc->next_ts = GST_CLOCK_TIME_NONE;
+
+ if (enc->need_channel_remap) {
+ buf = gst_buffer_make_writable (buf);
+ gst_wavpack_enc_fix_channel_order (enc, (gint32 *) GST_BUFFER_DATA (buf),
+ sample_count);
+ }
+
+ /* if we want to append the MD5 sum to the stream update it here
+ * with the current raw samples */
+ if (enc->md5) {
+ g_checksum_update (enc->md5_context, GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf));
+ }
+
+ /* encode and handle return values from encoding */
+ if (WavpackPackSamples (enc->wp_context, (int32_t *) GST_BUFFER_DATA (buf),
+ sample_count / enc->channels)) {
+ GST_DEBUG ("encoding samples successful");
+ ret = GST_FLOW_OK;
+ } else {
+ if ((enc->srcpad_last_return == GST_FLOW_RESEND) ||
+ (enc->wvcsrcpad_last_return == GST_FLOW_RESEND)) {
+ ret = GST_FLOW_RESEND;
+ } else if ((enc->srcpad_last_return == GST_FLOW_OK) ||
+ (enc->wvcsrcpad_last_return == GST_FLOW_OK)) {
+ ret = GST_FLOW_OK;
+ } else if ((enc->srcpad_last_return == GST_FLOW_NOT_LINKED) &&
+ (enc->wvcsrcpad_last_return == GST_FLOW_NOT_LINKED)) {
+ ret = GST_FLOW_NOT_LINKED;
+ } else if ((enc->srcpad_last_return == GST_FLOW_WRONG_STATE) &&
+ (enc->wvcsrcpad_last_return == GST_FLOW_WRONG_STATE)) {
+ ret = GST_FLOW_WRONG_STATE;
+ } else {
+ GST_ELEMENT_ERROR (enc, LIBRARY, ENCODE, (NULL),
+ ("encoding samples failed"));
+ ret = GST_FLOW_ERROR;
+ }
+ }
+
+ gst_buffer_unref (buf);
+ gst_object_unref (enc);
+ return ret;
+}
+
+static void
+gst_wavpack_enc_rewrite_first_block (GstWavpackEnc * enc)
+{
+ GstEvent *event = gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES,
+ 0, GST_BUFFER_OFFSET_NONE, 0);
+ gboolean ret;
+
+ g_return_if_fail (enc);
+ g_return_if_fail (enc->first_block);
+
+ /* update the sample count in the first block */
+ WavpackUpdateNumSamples (enc->wp_context, enc->first_block);
+
+ /* try to seek to the beginning of the output */
+ ret = gst_pad_push_event (enc->srcpad, event);
+ if (ret) {
+ /* try to rewrite the first block */
+ GST_DEBUG_OBJECT (enc, "rewriting first block ...");
+ enc->wv_id.passthrough = TRUE;
+ ret = gst_wavpack_enc_push_block (&enc->wv_id,
+ enc->first_block, enc->first_block_size);
+ enc->wv_id.passthrough = FALSE;
+ } else {
+ GST_WARNING_OBJECT (enc, "rewriting of first block failed. "
+ "Seeking to first block failed!");
+ }
+}
+
+static gboolean
+gst_wavpack_enc_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad));
+ gboolean ret = TRUE;
+
+ GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ /* Encode all remaining samples and flush them to the src pads */
+ WavpackFlushSamples (enc->wp_context);
+
+ /* Drop all remaining data, this is no complete block otherwise
+ * it would've been pushed already */
+ if (enc->pending_buffer) {
+ gst_buffer_unref (enc->pending_buffer);
+ enc->pending_buffer = NULL;
+ enc->pending_offset = 0;
+ }
+
+ /* write the MD5 sum if we have to write one */
+ if ((enc->md5) && (enc->md5_context)) {
+ guint8 md5_digest[16];
+ gsize digest_len = sizeof (md5_digest);
+
+ g_checksum_get_digest (enc->md5_context, md5_digest, &digest_len);
+ if (digest_len == sizeof (md5_digest))
+ WavpackStoreMD5Sum (enc->wp_context, md5_digest);
+ else
+ GST_WARNING_OBJECT (enc, "Calculating MD5 digest failed");
+ }
+
+ /* Try to rewrite the first frame with the correct sample number */
+ if (enc->first_block)
+ gst_wavpack_enc_rewrite_first_block (enc);
+
+ /* close the context if not already happened */
+ if (enc->wp_context) {
+ WavpackCloseFile (enc->wp_context);
+ enc->wp_context = NULL;
+ }
+
+ ret = gst_pad_event_default (pad, event);
+ break;
+ case GST_EVENT_NEWSEGMENT:
+ if (enc->wp_context) {
+ GST_WARNING_OBJECT (enc, "got NEWSEGMENT after encoding "
+ "already started");
+ }
+ /* drop NEWSEGMENT events, we create our own when pushing
+ * the first buffer to the pads */
+ gst_event_unref (event);
+ ret = TRUE;
+ break;
+ default:
+ ret = gst_pad_event_default (pad, event);
+ break;
+ }
+
+ gst_object_unref (enc);
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_wavpack_enc_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstWavpackEnc *enc = GST_WAVPACK_ENC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ /* set the last returned GstFlowReturns of the two pads to GST_FLOW_OK
+ * as they're only set to something else in WavpackPackSamples() or more
+ * specific gst_wavpack_enc_push_block() and nothing happened there yet */
+ enc->srcpad_last_return = enc->wvcsrcpad_last_return = GST_FLOW_OK;
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_wavpack_enc_reset (enc);
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static void
+gst_wavpack_enc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstWavpackEnc *enc = GST_WAVPACK_ENC (object);
+
+ switch (prop_id) {
+ case ARG_MODE:
+ enc->mode = g_value_get_enum (value);
+ break;
+ case ARG_BITRATE:{
+ guint val = g_value_get_uint (value);
+
+ if ((val >= 24000) && (val <= 9600000)) {
+ enc->bitrate = val;
+ enc->bps = 0.0;
+ } else {
+ enc->bitrate = 0;
+ enc->bps = 0.0;
+ }
+ break;
+ }
+ case ARG_BITSPERSAMPLE:{
+ gdouble val = g_value_get_double (value);
+
+ if ((val >= 2.0) && (val <= 24.0)) {
+ enc->bps = val;
+ enc->bitrate = 0;
+ } else {
+ enc->bps = 0.0;
+ enc->bitrate = 0;
+ }
+ break;
+ }
+ case ARG_CORRECTION_MODE:
+ enc->correction_mode = g_value_get_enum (value);
+ break;
+ case ARG_MD5:
+ enc->md5 = g_value_get_boolean (value);
+ break;
+ case ARG_EXTRA_PROCESSING:
+ enc->extra_processing = g_value_get_uint (value);
+ break;
+ case ARG_JOINT_STEREO_MODE:
+ enc->joint_stereo_mode = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_wavpack_enc_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstWavpackEnc *enc = GST_WAVPACK_ENC (object);
+
+ switch (prop_id) {
+ case ARG_MODE:
+ g_value_set_enum (value, enc->mode);
+ break;
+ case ARG_BITRATE:
+ if (enc->bps == 0.0) {
+ g_value_set_uint (value, enc->bitrate);
+ } else {
+ g_value_set_uint (value, 0);
+ }
+ break;
+ case ARG_BITSPERSAMPLE:
+ if (enc->bitrate == 0) {
+ g_value_set_double (value, enc->bps);
+ } else {
+ g_value_set_double (value, 0.0);
+ }
+ break;
+ case ARG_CORRECTION_MODE:
+ g_value_set_enum (value, enc->correction_mode);
+ break;
+ case ARG_MD5:
+ g_value_set_boolean (value, enc->md5);
+ break;
+ case ARG_EXTRA_PROCESSING:
+ g_value_set_uint (value, enc->extra_processing);
+ break;
+ case ARG_JOINT_STEREO_MODE:
+ g_value_set_enum (value, enc->joint_stereo_mode);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+gboolean
+gst_wavpack_enc_plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "wavpackenc",
+ GST_RANK_NONE, GST_TYPE_WAVPACK_ENC))
+ return FALSE;
+
+ GST_DEBUG_CATEGORY_INIT (gst_wavpack_enc_debug, "wavpack_enc", 0,
+ "Wavpack encoder");
+
+ return TRUE;
+}
diff --git a/ext/wavpack/gstwavpackenc.h b/ext/wavpack/gstwavpackenc.h
new file mode 100644
index 0000000..d2df844
--- /dev/null
+++ b/ext/wavpack/gstwavpackenc.h
@@ -0,0 +1,104 @@
+/* GStreamer Wavpack encoder plugin
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackenc.h: Wavpack audio encoder
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_WAVPACK_ENC_H__
+#define __GST_WAVPACK_ENC_H__
+
+#include <gst/gst.h>
+
+#include <wavpack/wavpack.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_WAVPACK_ENC \
+ (gst_wavpack_enc_get_type())
+#define GST_WAVPACK_ENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVPACK_ENC,GstWavpackEnc))
+#define GST_WAVPACK_ENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVPACK_ENC,GstWavpackEnc))
+#define GST_IS_WAVPACK_ENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVPACK_ENC))
+#define GST_IS_WAVPACK_ENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVPACK_ENC))
+typedef struct _GstWavpackEnc GstWavpackEnc;
+typedef struct _GstWavpackEncClass GstWavpackEncClass;
+
+typedef struct
+{
+ gboolean correction;
+ GstWavpackEnc *wavpack_enc;
+ gboolean passthrough;
+} GstWavpackEncWriteID;
+
+
+struct _GstWavpackEnc
+{
+ GstElement element;
+
+ /*< private > */
+ GstPad *sinkpad, *srcpad;
+ GstPad *wvcsrcpad;
+
+ GstFlowReturn srcpad_last_return;
+ GstFlowReturn wvcsrcpad_last_return;
+
+ WavpackConfig *wp_config;
+ WavpackContext *wp_context;
+
+ gint samplerate;
+ gint channels;
+ gint channel_mask;
+ gint8 channel_mapping[8];
+ gboolean need_channel_remap;
+ gint depth;
+
+ GstWavpackEncWriteID wv_id;
+ GstWavpackEncWriteID wvc_id;
+
+ guint mode;
+ guint bitrate;
+ gdouble bps;
+ guint correction_mode;
+ gboolean md5;
+ GChecksum *md5_context;
+ guint extra_processing;
+ guint joint_stereo_mode;
+
+ void *first_block;
+ int32_t first_block_size;
+
+ GstBuffer *pending_buffer;
+ gint32 pending_offset;
+
+ GstClockTime timestamp_offset;
+ GstClockTime next_ts;
+};
+
+struct _GstWavpackEncClass
+{
+ GstElementClass parent;
+};
+
+GType gst_wavpack_enc_get_type (void);
+
+gboolean gst_wavpack_enc_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_WAVPACK_ENC_H__ */
diff --git a/ext/wavpack/gstwavpackparse.c b/ext/wavpack/gstwavpackparse.c
new file mode 100644
index 0000000..e1ff785
--- /dev/null
+++ b/ext/wavpack/gstwavpackparse.c
@@ -0,0 +1,1344 @@
+/* GStreamer wavpack plugin
+ * Copyright (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (c) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackparse.c: wavpack file parser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-wavpackparse
+ *
+ * WavpackParse takes raw, unframed Wavpack streams and splits them into
+ * single Wavpack chunks with information like bit depth and the position
+ * in the stream.
+ * <ulink url="http://www.wavpack.com/">Wavpack</ulink> is an open-source
+ * audio codec that features both lossless and lossy encoding.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch filesrc location=test.wv ! wavpackparse ! wavpackdec ! fakesink
+ * ]| This pipeline decodes the Wavpack file test.wv into raw audio buffers.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include <gst/gst.h>
+#include <gst/gst-i18n-plugin.h>
+
+#include <math.h>
+#include <string.h>
+
+#include <wavpack/wavpack.h>
+#include "gstwavpackparse.h"
+#include "gstwavpackstreamreader.h"
+#include "gstwavpackcommon.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_wavpack_parse_debug);
+#define GST_CAT_DEFAULT gst_wavpack_parse_debug
+
+static inline GstWavpackParseIndexEntry *
+gst_wavpack_parse_index_entry_new (void)
+{
+ return g_slice_new (GstWavpackParseIndexEntry);
+}
+
+static inline void
+gst_wavpack_parse_index_entry_free (GstWavpackParseIndexEntry * entry)
+{
+ g_slice_free (GstWavpackParseIndexEntry, entry);
+}
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-wavpack, "
+ "framed = (boolean) false; "
+ "audio/x-wavpack-correction, " "framed = (boolean) false")
+ );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS ("audio/x-wavpack, "
+ "width = (int) [ 1, 32 ], "
+ "channels = (int) [ 1, 8 ], "
+ "rate = (int) [ 6000, 192000 ], " "framed = (boolean) true")
+ );
+
+static GstStaticPadTemplate wvc_src_factory = GST_STATIC_PAD_TEMPLATE ("wvcsrc",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS ("audio/x-wavpack-correction, " "framed = (boolean) true")
+ );
+
+static gboolean gst_wavpack_parse_sink_activate (GstPad * sinkpad);
+
+static gboolean
+gst_wavpack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active);
+
+static void gst_wavpack_parse_loop (GstElement * element);
+
+static GstStateChangeReturn gst_wavpack_parse_change_state (GstElement *
+ element, GstStateChange transition);
+static void gst_wavpack_parse_reset (GstWavpackParse * parse);
+
+static gint64 gst_wavpack_parse_get_upstream_length (GstWavpackParse * wvparse);
+
+static GstBuffer *gst_wavpack_parse_pull_buffer (GstWavpackParse * wvparse,
+ gint64 offset, guint size, GstFlowReturn * flow);
+static GstFlowReturn gst_wavpack_parse_chain (GstPad * pad, GstBuffer * buf);
+
+GST_BOILERPLATE (GstWavpackParse, gst_wavpack_parse, GstElement,
+ GST_TYPE_ELEMENT);
+
+static void
+gst_wavpack_parse_base_init (gpointer klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_static_pad_template (element_class, &src_factory);
+ gst_element_class_add_static_pad_template (element_class,
+ &wvc_src_factory);
+ gst_element_class_add_static_pad_template (element_class, &sink_factory);
+
+ gst_element_class_set_details_simple (element_class, "Wavpack parser",
+ "Codec/Demuxer/Audio",
+ "Parses Wavpack files",
+ "Arwed v. Merkatz <v.merkatz@gmx.net>, "
+ "Sebastian Dröge <slomo@circular-chaos.org>");
+}
+
+static void
+gst_wavpack_parse_finalize (GObject * object)
+{
+ gst_wavpack_parse_reset (GST_WAVPACK_PARSE (object));
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_wavpack_parse_class_init (GstWavpackParseClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = gst_wavpack_parse_finalize;
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_wavpack_parse_change_state);
+}
+
+static GstWavpackParseIndexEntry *
+gst_wavpack_parse_index_get_last_entry (GstWavpackParse * wvparse)
+{
+ g_assert (wvparse->entries != NULL);
+
+ return wvparse->entries->data;
+}
+
+static GstWavpackParseIndexEntry *
+gst_wavpack_parse_index_get_entry_from_sample (GstWavpackParse * wvparse,
+ gint64 sample_offset)
+{
+ gint i;
+
+ GSList *node;
+
+ if (wvparse->entries == NULL)
+ return NULL;
+
+ for (node = wvparse->entries, i = 0; node; node = node->next, i++) {
+ GstWavpackParseIndexEntry *entry;
+
+ entry = node->data;
+
+ GST_LOG_OBJECT (wvparse, "Index entry %03u: sample %" G_GINT64_FORMAT " @"
+ " byte %" G_GINT64_FORMAT, i, entry->sample_offset, entry->byte_offset);
+
+ if (entry->sample_offset <= sample_offset &&
+ sample_offset < entry->sample_offset_end) {
+ GST_LOG_OBJECT (wvparse, "found match");
+ return entry;
+ }
+
+ /* as the list is sorted and we first look at the latest entry
+ * we can abort searching for an entry if the sample we want is
+ * after the latest one */
+ if (sample_offset >= entry->sample_offset_end)
+ break;
+ }
+ GST_LOG_OBJECT (wvparse, "no match in index");
+ return NULL;
+}
+
+static void
+gst_wavpack_parse_index_append_entry (GstWavpackParse * wvparse,
+ gint64 byte_offset, gint64 sample_offset, gint64 num_samples)
+{
+ GstWavpackParseIndexEntry *entry;
+
+ /* do we have this one already? */
+ if (wvparse->entries) {
+ entry = gst_wavpack_parse_index_get_last_entry (wvparse);
+ if (entry->byte_offset >= byte_offset
+ || entry->sample_offset >= sample_offset)
+ return;
+ }
+
+ GST_LOG_OBJECT (wvparse, "Adding index entry %8" G_GINT64_FORMAT " - %"
+ GST_TIME_FORMAT " @ offset 0x%08" G_GINT64_MODIFIER "x", sample_offset,
+ GST_TIME_ARGS (gst_util_uint64_scale_int (sample_offset,
+ GST_SECOND, wvparse->samplerate)), byte_offset);
+
+ entry = gst_wavpack_parse_index_entry_new ();
+ entry->byte_offset = byte_offset;
+ entry->sample_offset = sample_offset;
+ entry->sample_offset_end = sample_offset + num_samples;
+ wvparse->entries = g_slist_prepend (wvparse->entries, entry);
+}
+
+static void
+gst_wavpack_parse_reset (GstWavpackParse * parse)
+{
+ parse->total_samples = G_GINT64_CONSTANT (-1);
+ parse->samplerate = 0;
+ parse->channels = 0;
+
+ gst_segment_init (&parse->segment, GST_FORMAT_UNDEFINED);
+ parse->next_block_index = 0;
+
+ parse->current_offset = 0;
+ parse->need_newsegment = TRUE;
+ parse->discont = TRUE;
+ parse->upstream_length = -1;
+
+ if (parse->entries) {
+ g_slist_foreach (parse->entries, (GFunc) gst_wavpack_parse_index_entry_free,
+ NULL);
+ g_slist_free (parse->entries);
+ parse->entries = NULL;
+ }
+
+ if (parse->adapter) {
+ gst_adapter_clear (parse->adapter);
+ g_object_unref (parse->adapter);
+ parse->adapter = NULL;
+ }
+
+ if (parse->srcpad != NULL) {
+ gboolean res;
+
+ GST_DEBUG_OBJECT (parse, "Removing src pad");
+ res = gst_element_remove_pad (GST_ELEMENT (parse), parse->srcpad);
+ g_return_if_fail (res != FALSE);
+ gst_object_unref (parse->srcpad);
+ parse->srcpad = NULL;
+ }
+
+ g_list_foreach (parse->queued_events, (GFunc) gst_mini_object_unref, NULL);
+ g_list_free (parse->queued_events);
+ parse->queued_events = NULL;
+
+ if (parse->pending_buffer)
+ gst_buffer_unref (parse->pending_buffer);
+
+ parse->pending_buffer = NULL;
+}
+
+static const GstQueryType *
+gst_wavpack_parse_get_src_query_types (GstPad * pad)
+{
+ static const GstQueryType types[] = {
+ GST_QUERY_POSITION,
+ GST_QUERY_DURATION,
+ GST_QUERY_SEEKING,
+ 0
+ };
+
+ return types;
+}
+
+static gboolean
+gst_wavpack_parse_src_query (GstPad * pad, GstQuery * query)
+{
+ GstWavpackParse *parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));
+
+ GstFormat format;
+
+ gboolean ret = FALSE;
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_POSITION:{
+ gint64 cur;
+
+ guint rate;
+
+ GST_OBJECT_LOCK (parse);
+ cur = parse->segment.last_stop;
+ rate = parse->samplerate;
+ GST_OBJECT_UNLOCK (parse);
+
+ if (rate == 0) {
+ GST_DEBUG_OBJECT (parse, "haven't read header yet");
+ break;
+ }
+
+ gst_query_parse_position (query, &format, NULL);
+
+ switch (format) {
+ case GST_FORMAT_TIME:
+ cur = gst_util_uint64_scale_int (cur, GST_SECOND, rate);
+ gst_query_set_position (query, GST_FORMAT_TIME, cur);
+ ret = TRUE;
+ break;
+ case GST_FORMAT_DEFAULT:
+ gst_query_set_position (query, GST_FORMAT_DEFAULT, cur);
+ ret = TRUE;
+ break;
+ default:
+ GST_DEBUG_OBJECT (parse, "cannot handle position query in "
+ "%s format. Forwarding upstream.", gst_format_get_name (format));
+ ret = gst_pad_query_default (pad, query);
+ break;
+ }
+ break;
+ }
+ case GST_QUERY_DURATION:{
+ gint64 len;
+
+ guint rate;
+
+ GST_OBJECT_LOCK (parse);
+ rate = parse->samplerate;
+ len = parse->total_samples;
+ GST_OBJECT_UNLOCK (parse);
+
+ if (rate == 0) {
+ GST_DEBUG_OBJECT (parse, "haven't read header yet");
+ break;
+ }
+
+ gst_query_parse_duration (query, &format, NULL);
+
+ switch (format) {
+ case GST_FORMAT_TIME:
+ if (len != G_GINT64_CONSTANT (-1))
+ len = gst_util_uint64_scale_int (len, GST_SECOND, rate);
+ gst_query_set_duration (query, GST_FORMAT_TIME, len);
+ ret = TRUE;
+ break;
+ case GST_FORMAT_DEFAULT:
+ gst_query_set_duration (query, GST_FORMAT_DEFAULT, len);
+ ret = TRUE;
+ break;
+ default:
+ GST_DEBUG_OBJECT (parse, "cannot handle duration query in "
+ "%s format. Forwarding upstream.", gst_format_get_name (format));
+ ret = gst_pad_query_default (pad, query);
+ break;
+ }
+ break;
+ }
+ case GST_QUERY_SEEKING:{
+ gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
+ if (format == GST_FORMAT_TIME || format == GST_FORMAT_DEFAULT) {
+ gboolean seekable;
+
+ gint64 duration = -1;
+
+ /* only fails if we didn't read the headers yet and can't say
+ * anything about our seeking capabilities */
+ if (!gst_pad_query_duration (pad, &format, &duration))
+ break;
+
+ /* can't seek in streaming mode yet */
+ GST_OBJECT_LOCK (parse);
+ seekable = (parse->adapter == NULL);
+ GST_OBJECT_UNLOCK (parse);
+
+ gst_query_set_seeking (query, format, seekable, 0, duration);
+ ret = TRUE;
+ }
+ break;
+ }
+ default:{
+ ret = gst_pad_query_default (pad, query);
+ break;
+ }
+ }
+
+ gst_object_unref (parse);
+ return ret;
+
+}
+
+/* returns TRUE on success, with byte_offset set to the offset of the
+ * wavpack chunk containing the sample requested. start_sample will be
+ * set to the first sample in the chunk starting at byte_offset.
+ * Scanning from the last known header offset to the wanted position
+ * when seeking forward isn't very clever, but seems fast enough in
+ * practice and has the nice side effect of populating our index
+ * table */
+static gboolean
+gst_wavpack_parse_scan_to_find_sample (GstWavpackParse * parse,
+ gint64 sample, gint64 * byte_offset, gint64 * start_sample)
+{
+ GstWavpackParseIndexEntry *entry;
+
+ GstFlowReturn ret;
+
+ gint64 off = 0;
+
+ /* first, check if we have to scan at all */
+ entry = gst_wavpack_parse_index_get_entry_from_sample (parse, sample);
+ if (entry) {
+ *byte_offset = entry->byte_offset;
+ *start_sample = entry->sample_offset;
+ GST_LOG_OBJECT (parse, "Found index entry: sample %" G_GINT64_FORMAT
+ " @ offset %" G_GINT64_FORMAT, entry->sample_offset,
+ entry->byte_offset);
+ return TRUE;
+ }
+
+ GST_LOG_OBJECT (parse, "No matching entry in index, scanning file ...");
+
+ /* if we have an index, we can start scanning from the last known offset
+ * in there, after all we know our wanted sample is not in the index */
+ if (parse->entries) {
+ GstWavpackParseIndexEntry *entry;
+
+ entry = gst_wavpack_parse_index_get_last_entry (parse);
+ off = entry->byte_offset;
+ }
+
+ /* now scan forward until we find the chunk we're looking for or hit EOS */
+ do {
+ WavpackHeader header;
+
+ GstBuffer *buf;
+
+ buf = gst_wavpack_parse_pull_buffer (parse, off, sizeof (WavpackHeader),
+ &ret);
+
+ if (buf == NULL)
+ break;
+
+ gst_wavpack_read_header (&header, GST_BUFFER_DATA (buf));
+ gst_buffer_unref (buf);
+
+ if (header.flags & INITIAL_BLOCK)
+ gst_wavpack_parse_index_append_entry (parse, off, header.block_index,
+ header.block_samples);
+ else
+ continue;
+
+ if (header.block_index <= sample &&
+ sample < (header.block_index + header.block_samples)) {
+ *byte_offset = off;
+ *start_sample = header.block_index;
+ return TRUE;
+ }
+
+ off += header.ckSize + 8;
+ } while (1);
+
+ GST_DEBUG_OBJECT (parse, "scan failed: %s (off=0x%08" G_GINT64_MODIFIER "x)",
+ gst_flow_get_name (ret), off);
+
+ return FALSE;
+}
+
+static gboolean
+gst_wavpack_parse_send_newsegment (GstWavpackParse * wvparse, gboolean update)
+{
+ GstSegment *s = &wvparse->segment;
+
+ gboolean ret;
+
+ gint64 stop_time = -1;
+
+ gint64 start_time = 0;
+
+ gint64 cur_pos_time;
+
+ gint64 diff;
+
+ /* segment is in DEFAULT format, but we want to send a TIME newsegment */
+ start_time = gst_util_uint64_scale_int (s->start, GST_SECOND,
+ wvparse->samplerate);
+
+ if (s->stop != -1) {
+ stop_time = gst_util_uint64_scale_int (s->stop, GST_SECOND,
+ wvparse->samplerate);
+ }
+
+ GST_DEBUG_OBJECT (wvparse, "sending newsegment from %" GST_TIME_FORMAT
+ " to %" GST_TIME_FORMAT, GST_TIME_ARGS (start_time),
+ GST_TIME_ARGS (stop_time));
+
+ /* after a seek, s->last_stop will point to a chunk boundary, ie. from
+ * which sample we will start sending data again, while s->start will
+ * point to the sample we actually want to seek to and want to start
+ * playing right after the seek. Adjust clock-time for the difference
+ * so we start playing from start_time */
+ cur_pos_time = gst_util_uint64_scale_int (s->last_stop, GST_SECOND,
+ wvparse->samplerate);
+ diff = start_time - cur_pos_time;
+
+ ret = gst_pad_push_event (wvparse->srcpad,
+ gst_event_new_new_segment (update, s->rate, GST_FORMAT_TIME,
+ start_time, stop_time, start_time - diff));
+
+ return ret;
+}
+
+static gboolean
+gst_wavpack_parse_handle_seek_event (GstWavpackParse * wvparse,
+ GstEvent * event)
+{
+ GstSeekFlags seek_flags;
+
+ GstSeekType start_type;
+
+ GstSeekType stop_type;
+
+ GstSegment segment;
+
+ GstFormat format;
+
+ gboolean only_update;
+
+ gboolean flush, ret;
+
+ gdouble speed;
+
+ gint64 stop;
+
+ gint64 start; /* sample we want to seek to */
+
+ gint64 byte_offset; /* byte offset the chunk we seek to starts at */
+
+ gint64 chunk_start; /* first sample in chunk we seek to */
+
+ guint rate;
+
+ gint64 last_stop;
+
+ if (wvparse->adapter) {
+ GST_DEBUG_OBJECT (wvparse, "seeking in streaming mode not implemented yet");
+ return FALSE;
+ }
+
+ gst_event_parse_seek (event, &speed, &format, &seek_flags, &start_type,
+ &start, &stop_type, &stop);
+
+ if (format != GST_FORMAT_DEFAULT && format != GST_FORMAT_TIME) {
+ GST_DEBUG ("seeking is only supported in TIME or DEFAULT format");
+ return FALSE;
+ }
+
+ if (speed < 0.0) {
+ GST_DEBUG ("only forward playback supported, rate %f not allowed", speed);
+ return FALSE;
+ }
+
+ GST_OBJECT_LOCK (wvparse);
+
+ rate = wvparse->samplerate;
+ if (rate == 0) {
+ GST_OBJECT_UNLOCK (wvparse);
+ GST_DEBUG ("haven't read header yet");
+ return FALSE;
+ }
+
+ /* figure out the last position we need to play. If it's configured (stop !=
+ * -1), use that, else we play until the total duration of the file */
+ if (stop == -1)
+ stop = wvparse->segment.duration;
+
+ /* convert from time to samples if necessary */
+ if (format == GST_FORMAT_TIME) {
+ if (start_type != GST_SEEK_TYPE_NONE)
+ start = gst_util_uint64_scale_int (start, rate, GST_SECOND);
+ if (stop_type != GST_SEEK_TYPE_NONE)
+ stop = gst_util_uint64_scale_int (stop, rate, GST_SECOND);
+ }
+
+ if (start < 0) {
+ GST_OBJECT_UNLOCK (wvparse);
+ GST_DEBUG_OBJECT (wvparse, "Invalid start sample %" G_GINT64_FORMAT, start);
+ return FALSE;
+ }
+
+ flush = ((seek_flags & GST_SEEK_FLAG_FLUSH) != 0);
+
+ /* operate on segment copy until we know the seek worked */
+ segment = wvparse->segment;
+
+ gst_segment_set_seek (&segment, speed, GST_FORMAT_DEFAULT,
+ seek_flags, start_type, start, stop_type, stop, &only_update);
+
+#if 0
+ if (only_update) {
+ wvparse->segment = segment;
+ gst_wavpack_parse_send_newsegment (wvparse, TRUE);
+ goto done;
+ }
+#endif
+
+ gst_pad_push_event (wvparse->sinkpad, gst_event_new_flush_start ());
+
+ if (flush) {
+ gst_pad_push_event (wvparse->srcpad, gst_event_new_flush_start ());
+ } else {
+ gst_pad_pause_task (wvparse->sinkpad);
+ }
+
+ GST_PAD_STREAM_LOCK (wvparse->sinkpad);
+
+ /* Save current position */
+ last_stop = wvparse->segment.last_stop;
+
+ gst_pad_push_event (wvparse->sinkpad, gst_event_new_flush_stop ());
+
+ if (flush) {
+ gst_pad_push_event (wvparse->srcpad, gst_event_new_flush_stop ());
+ }
+
+ GST_DEBUG_OBJECT (wvparse, "Performing seek to %" GST_TIME_FORMAT " sample %"
+ G_GINT64_FORMAT, GST_TIME_ARGS (segment.start * GST_SECOND / rate),
+ start);
+
+ ret = gst_wavpack_parse_scan_to_find_sample (wvparse, segment.start,
+ &byte_offset, &chunk_start);
+
+ if (ret) {
+ GST_DEBUG_OBJECT (wvparse, "new offset: %" G_GINT64_FORMAT, byte_offset);
+ wvparse->current_offset = byte_offset;
+ /* we want to send a newsegment event with the actual seek position
+ * as start, even though our first buffer might start before the
+ * configured segment. We leave it up to the decoder or sink to crop
+ * the output buffers accordingly */
+ wvparse->segment = segment;
+ wvparse->segment.last_stop = chunk_start;
+ wvparse->need_newsegment = TRUE;
+ wvparse->discont = (last_stop != chunk_start) ? TRUE : FALSE;
+
+ /* if we're doing a segment seek, post a SEGMENT_START message */
+ if (wvparse->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+ gst_element_post_message (GST_ELEMENT_CAST (wvparse),
+ gst_message_new_segment_start (GST_OBJECT_CAST (wvparse),
+ wvparse->segment.format, wvparse->segment.last_stop));
+ }
+ } else {
+ GST_DEBUG_OBJECT (wvparse, "seek failed: don't know where to seek to");
+ }
+
+ GST_PAD_STREAM_UNLOCK (wvparse->sinkpad);
+ GST_OBJECT_UNLOCK (wvparse);
+
+ gst_pad_start_task (wvparse->sinkpad,
+ (GstTaskFunction) gst_wavpack_parse_loop, wvparse);
+
+ return ret;
+}
+
+static gboolean
+gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstWavpackParse *parse;
+
+ gboolean ret = TRUE;
+
+ parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:{
+ if (parse->adapter) {
+ gst_adapter_clear (parse->adapter);
+ }
+ if (parse->pending_buffer) {
+ gst_buffer_unref (parse->pending_buffer);
+ parse->pending_buffer = NULL;
+ parse->pending_offset = 0;
+ }
+ ret = gst_pad_push_event (parse->srcpad, event);
+ break;
+ }
+ case GST_EVENT_NEWSEGMENT:{
+ parse->need_newsegment = TRUE;
+ gst_event_unref (event);
+ ret = TRUE;
+ break;
+ }
+ case GST_EVENT_EOS:{
+ if (parse->adapter) {
+ /* remove all bytes that are left in the adapter after EOS. They can't
+ * be a complete Wavpack block and we can't do anything with them */
+ gst_adapter_clear (parse->adapter);
+ }
+ if (parse->pending_buffer) {
+ gst_buffer_unref (parse->pending_buffer);
+ parse->pending_buffer = NULL;
+ parse->pending_offset = 0;
+ }
+ ret = gst_pad_push_event (parse->srcpad, event);
+ break;
+ }
+ default:{
+ /* stream lock is recursive, should be fine for all events */
+ GST_PAD_STREAM_LOCK (pad);
+ if (parse->srcpad == NULL) {
+ parse->queued_events = g_list_append (parse->queued_events, event);
+ } else {
+ ret = gst_pad_push_event (parse->srcpad, event);
+ }
+ GST_PAD_STREAM_UNLOCK (pad);
+ }
+ }
+
+
+ gst_object_unref (parse);
+ return ret;
+}
+
+static gboolean
+gst_wavpack_parse_src_event (GstPad * pad, GstEvent * event)
+{
+ GstWavpackParse *parse;
+
+ gboolean ret;
+
+ parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ ret = gst_wavpack_parse_handle_seek_event (parse, event);
+ break;
+ default:
+ ret = gst_pad_event_default (pad, event);
+ break;
+ }
+
+ gst_object_unref (parse);
+ return ret;
+}
+
+static void
+gst_wavpack_parse_init (GstWavpackParse * parse, GstWavpackParseClass * gclass)
+{
+ GstElementClass *klass = GST_ELEMENT_GET_CLASS (parse);
+
+ GstPadTemplate *tmpl;
+
+ tmpl = gst_element_class_get_pad_template (klass, "sink");
+ parse->sinkpad = gst_pad_new_from_template (tmpl, "sink");
+
+ gst_pad_set_activate_function (parse->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_activate));
+ gst_pad_set_activatepull_function (parse->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_activate_pull));
+ gst_pad_set_event_function (parse->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_event));
+ gst_pad_set_chain_function (parse->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_parse_chain));
+
+ gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
+
+ parse->srcpad = NULL;
+ gst_wavpack_parse_reset (parse);
+}
+
+static gint64
+gst_wavpack_parse_get_upstream_length (GstWavpackParse * parse)
+{
+ gint64 length = -1;
+
+ GstFormat format = GST_FORMAT_BYTES;
+
+ if (!gst_pad_query_peer_duration (parse->sinkpad, &format, &length)) {
+ length = -1;
+ } else {
+ GST_DEBUG ("upstream length: %" G_GINT64_FORMAT, length);
+ }
+ return length;
+}
+
+static GstBuffer *
+gst_wavpack_parse_pull_buffer (GstWavpackParse * wvparse, gint64 offset,
+ guint size, GstFlowReturn * flow)
+{
+ GstFlowReturn flow_ret;
+
+ GstBuffer *buf = NULL;
+
+ if (offset + size > wvparse->upstream_length) {
+ wvparse->upstream_length = gst_wavpack_parse_get_upstream_length (wvparse);
+ if (offset + size > wvparse->upstream_length) {
+ GST_DEBUG_OBJECT (wvparse, "EOS: %" G_GINT64_FORMAT " + %u > %"
+ G_GINT64_FORMAT, offset, size, wvparse->upstream_length);
+ flow_ret = GST_FLOW_UNEXPECTED;
+ goto done;
+ }
+ }
+
+ flow_ret = gst_pad_pull_range (wvparse->sinkpad, offset, size, &buf);
+
+ if (flow_ret != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (wvparse, "pull_range (%" G_GINT64_FORMAT ", %u) "
+ "failed, flow: %s", offset, size, gst_flow_get_name (flow_ret));
+ buf = NULL;
+ goto done;
+ }
+
+ if (GST_BUFFER_SIZE (buf) < size) {
+ GST_DEBUG_OBJECT (wvparse, "Short read at offset %" G_GINT64_FORMAT
+ ", got only %u of %u bytes", offset, GST_BUFFER_SIZE (buf), size);
+ gst_buffer_unref (buf);
+ buf = NULL;
+ flow_ret = GST_FLOW_UNEXPECTED;
+ }
+
+done:
+ if (flow)
+ *flow = flow_ret;
+ return buf;
+}
+
+static gboolean
+gst_wavpack_parse_create_src_pad (GstWavpackParse * wvparse, GstBuffer * buf,
+ WavpackHeader * header)
+{
+ GstWavpackMetadata meta;
+
+ GstCaps *caps = NULL;
+
+ guchar *bufptr;
+
+ g_assert (wvparse->srcpad == NULL);
+
+ bufptr = GST_BUFFER_DATA (buf) + sizeof (WavpackHeader);
+
+ while (gst_wavpack_read_metadata (&meta, GST_BUFFER_DATA (buf), &bufptr)) {
+ switch (meta.id) {
+ case ID_WVC_BITSTREAM:{
+ caps = gst_caps_new_simple ("audio/x-wavpack-correction",
+ "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+ wvparse->srcpad =
+ gst_pad_new_from_template (gst_element_class_get_pad_template
+ (GST_ELEMENT_GET_CLASS (wvparse), "wvcsrc"), "wvcsrc");
+ break;
+ }
+ case ID_WV_BITSTREAM:
+ case ID_WVX_BITSTREAM:{
+ WavpackStreamReader *stream_reader = gst_wavpack_stream_reader_new ();
+
+ WavpackContext *wpc;
+
+ gchar error_msg[80];
+
+ read_id rid;
+
+ gint channel_mask;
+
+ rid.buffer = GST_BUFFER_DATA (buf);
+ rid.length = GST_BUFFER_SIZE (buf);
+ rid.position = 0;
+
+ wpc =
+ WavpackOpenFileInputEx (stream_reader, &rid, NULL, error_msg, 0, 0);
+
+ if (!wpc)
+ return FALSE;
+
+ wvparse->samplerate = WavpackGetSampleRate (wpc);
+ wvparse->channels = WavpackGetNumChannels (wpc);
+ wvparse->total_samples =
+ (header->total_samples ==
+ 0xffffffff) ? G_GINT64_CONSTANT (-1) : header->total_samples;
+
+ caps = gst_caps_new_simple ("audio/x-wavpack",
+ "width", G_TYPE_INT, WavpackGetBitsPerSample (wpc),
+ "channels", G_TYPE_INT, wvparse->channels,
+ "rate", G_TYPE_INT, wvparse->samplerate,
+ "framed", G_TYPE_BOOLEAN, TRUE, NULL);
+#ifdef WAVPACK_OLD_API
+ channel_mask = wpc->config.channel_mask;
+#else
+ channel_mask = WavpackGetChannelMask (wpc);
+#endif
+ if (channel_mask == 0)
+ channel_mask =
+ gst_wavpack_get_default_channel_mask (wvparse->channels);
+
+ if (channel_mask != 0) {
+ if (!gst_wavpack_set_channel_layout (caps, channel_mask)) {
+ GST_WARNING_OBJECT (wvparse, "Failed to set channel layout");
+ gst_caps_unref (caps);
+ caps = NULL;
+ WavpackCloseFile (wpc);
+ g_free (stream_reader);
+ break;
+ }
+ }
+
+ wvparse->srcpad =
+ gst_pad_new_from_template (gst_element_class_get_pad_template
+ (GST_ELEMENT_GET_CLASS (wvparse), "src"), "src");
+ WavpackCloseFile (wpc);
+ g_free (stream_reader);
+ break;
+ }
+ default:{
+ GST_LOG_OBJECT (wvparse, "unhandled ID: 0x%02x", meta.id);
+ break;
+ }
+ }
+ if (caps != NULL)
+ break;
+ }
+
+ if (caps == NULL || wvparse->srcpad == NULL)
+ return FALSE;
+
+ GST_DEBUG_OBJECT (wvparse, "Added src pad with caps %" GST_PTR_FORMAT, caps);
+
+ gst_pad_set_query_function (wvparse->srcpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_query));
+ gst_pad_set_query_type_function (wvparse->srcpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_parse_get_src_query_types));
+ gst_pad_set_event_function (wvparse->srcpad,
+ GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_event));
+
+ gst_pad_set_caps (wvparse->srcpad, caps);
+ gst_caps_unref (caps);
+ gst_pad_use_fixed_caps (wvparse->srcpad);
+
+ gst_object_ref (wvparse->srcpad);
+ gst_pad_set_active (wvparse->srcpad, TRUE);
+ gst_element_add_pad (GST_ELEMENT (wvparse), wvparse->srcpad);
+ gst_element_no_more_pads (GST_ELEMENT (wvparse));
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_wavpack_parse_push_buffer (GstWavpackParse * wvparse, GstBuffer * buf,
+ WavpackHeader * header)
+{
+ GstFlowReturn ret;
+ wvparse->current_offset += header->ckSize + 8;
+
+ wvparse->segment.last_stop = header->block_index;
+
+ if (wvparse->need_newsegment) {
+ if (gst_wavpack_parse_send_newsegment (wvparse, FALSE))
+ wvparse->need_newsegment = FALSE;
+ }
+
+ /* send any queued events */
+ if (wvparse->queued_events) {
+ GList *l;
+
+ for (l = wvparse->queued_events; l != NULL; l = l->next) {
+ gst_pad_push_event (wvparse->srcpad, GST_EVENT (l->data));
+ }
+ g_list_free (wvparse->queued_events);
+ wvparse->queued_events = NULL;
+ }
+
+ if (wvparse->pending_buffer == NULL) {
+ wvparse->pending_buffer = buf;
+ wvparse->pending_offset = header->block_index;
+ } else if (wvparse->pending_offset == header->block_index) {
+ wvparse->pending_buffer = gst_buffer_join (wvparse->pending_buffer, buf);
+ } else {
+ GST_ERROR ("Got incomplete block, dropping");
+ gst_buffer_unref (wvparse->pending_buffer);
+ wvparse->pending_buffer = buf;
+ wvparse->pending_offset = header->block_index;
+ }
+
+ if (!(header->flags & FINAL_BLOCK))
+ return GST_FLOW_OK;
+
+ buf = wvparse->pending_buffer;
+ wvparse->pending_buffer = NULL;
+
+ GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (header->block_index,
+ GST_SECOND, wvparse->samplerate);
+ GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (header->block_samples,
+ GST_SECOND, wvparse->samplerate);
+ GST_BUFFER_OFFSET (buf) = header->block_index;
+ GST_BUFFER_OFFSET_END (buf) = header->block_index + header->block_samples;
+
+ if (wvparse->discont || wvparse->next_block_index != header->block_index) {
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+ wvparse->discont = FALSE;
+ }
+
+ wvparse->next_block_index = header->block_index + header->block_samples;
+
+ gst_buffer_set_caps (buf, GST_PAD_CAPS (wvparse->srcpad));
+
+ GST_LOG_OBJECT (wvparse, "Pushing buffer with time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+ ret = gst_pad_push (wvparse->srcpad, buf);
+
+ wvparse->segment.last_stop = wvparse->next_block_index;
+
+ return ret;
+}
+
+static guint8 *
+gst_wavpack_parse_find_marker (guint8 * buf, guint size)
+{
+ int i;
+
+ guint8 *ret = NULL;
+
+ if (G_UNLIKELY (size < 4))
+ return NULL;
+
+ for (i = 0; i < size - 4; i++) {
+ if (memcmp (buf + i, "wvpk", 4) == 0) {
+ ret = buf + i;
+ break;
+ }
+ }
+ return ret;
+}
+
+static GstFlowReturn
+gst_wavpack_parse_resync_loop (GstWavpackParse * parse, WavpackHeader * header)
+{
+ GstFlowReturn flow_ret = GST_FLOW_UNEXPECTED;
+
+ GstBuffer *buf = NULL;
+
+ /* loop until we have a frame header or reach the end of the stream */
+ while (1) {
+ guint8 *data, *marker;
+
+ guint len, size;
+
+ if (buf) {
+ gst_buffer_unref (buf);
+ buf = NULL;
+ }
+
+ if (parse->upstream_length == 0 ||
+ parse->upstream_length <= parse->current_offset) {
+ parse->upstream_length = gst_wavpack_parse_get_upstream_length (parse);
+ if (parse->upstream_length == 0 ||
+ parse->upstream_length <= parse->current_offset) {
+ break;
+ }
+ }
+
+ len = MIN (parse->upstream_length - parse->current_offset, 2048);
+
+ GST_LOG_OBJECT (parse, "offset: %" G_GINT64_FORMAT, parse->current_offset);
+
+ buf = gst_wavpack_parse_pull_buffer (parse, parse->current_offset,
+ len, &flow_ret);
+
+ /* whatever the problem is, there's nothing more for us to do for now */
+ if (flow_ret != GST_FLOW_OK)
+ break;
+
+ data = GST_BUFFER_DATA (buf);
+ size = GST_BUFFER_SIZE (buf);
+
+ /* not enough data for a header? */
+ if (size < sizeof (WavpackHeader))
+ break;
+
+ /* got a header right where we are at now? */
+ if (gst_wavpack_read_header (header, data))
+ break;
+
+ /* nope, let's see if we can find one */
+ marker = gst_wavpack_parse_find_marker (data + 1, size - 1);
+
+ if (marker) {
+ parse->current_offset += marker - data;
+ /* do one more loop iteration to make sure we pull enough
+ * data for a full header, we'll bail out then */
+ } else {
+ parse->current_offset += len - 4;
+ }
+ }
+
+ if (buf)
+ gst_buffer_unref (buf);
+
+ return flow_ret;
+}
+
+static void
+gst_wavpack_parse_loop (GstElement * element)
+{
+ GstWavpackParse *parse = GST_WAVPACK_PARSE (element);
+
+ GstFlowReturn flow_ret;
+ WavpackHeader header = { {0,}, 0, };
+ GstBuffer *buf = NULL;
+
+ flow_ret = gst_wavpack_parse_resync_loop (parse, &header);
+
+ if (flow_ret != GST_FLOW_OK)
+ goto pause;
+
+ GST_LOG_OBJECT (parse, "Read header at offset %" G_GINT64_FORMAT
+ ": chunk size = %u+8", parse->current_offset, header.ckSize);
+
+ buf = gst_wavpack_parse_pull_buffer (parse, parse->current_offset,
+ header.ckSize + 8, &flow_ret);
+
+ if (flow_ret != GST_FLOW_OK)
+ goto pause;
+
+ if (parse->srcpad == NULL) {
+ if (!gst_wavpack_parse_create_src_pad (parse, buf, &header)) {
+ GST_ERROR_OBJECT (parse, "Failed to create src pad");
+ flow_ret = GST_FLOW_ERROR;
+ goto pause;
+ }
+ }
+ if (header.flags & INITIAL_BLOCK)
+ gst_wavpack_parse_index_append_entry (parse, parse->current_offset,
+ header.block_index, header.block_samples);
+
+ flow_ret = gst_wavpack_parse_push_buffer (parse, buf, &header);
+ if (flow_ret != GST_FLOW_OK)
+ goto pause;
+
+ return;
+
+pause:
+ {
+ const gchar *reason = gst_flow_get_name (flow_ret);
+
+ GST_LOG_OBJECT (parse, "pausing task, reason %s", reason);
+ gst_pad_pause_task (parse->sinkpad);
+
+ if (flow_ret == GST_FLOW_UNEXPECTED && parse->srcpad) {
+ if (parse->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+ GstClockTime stop;
+
+ GST_LOG_OBJECT (parse, "Sending segment done");
+
+ if ((stop = parse->segment.stop) == -1)
+ stop = parse->segment.duration;
+
+ gst_element_post_message (GST_ELEMENT_CAST (parse),
+ gst_message_new_segment_done (GST_OBJECT_CAST (parse),
+ parse->segment.format, stop));
+ } else {
+ GST_LOG_OBJECT (parse, "Sending EOS, at end of stream");
+ gst_pad_push_event (parse->srcpad, gst_event_new_eos ());
+ }
+ } else if (flow_ret == GST_FLOW_NOT_LINKED
+ || flow_ret < GST_FLOW_UNEXPECTED) {
+ GST_ELEMENT_ERROR (parse, STREAM, FAILED,
+ (_("Internal data stream error.")), ("stream stopped, reason %s",
+ reason));
+ if (parse->srcpad)
+ gst_pad_push_event (parse->srcpad, gst_event_new_eos ());
+ }
+ return;
+ }
+}
+
+static gboolean
+gst_wavpack_parse_resync_adapter (GstAdapter * adapter)
+{
+ const guint8 *buf, *marker;
+
+ guint avail = gst_adapter_available (adapter);
+
+ if (avail < 4)
+ return FALSE;
+
+ /* if the marker is at the beginning don't do the expensive search */
+ buf = gst_adapter_peek (adapter, 4);
+ if (memcmp (buf, "wvpk", 4) == 0)
+ return TRUE;
+
+ if (avail == 4)
+ return FALSE;
+
+ /* search for the marker in the complete content of the adapter */
+ buf = gst_adapter_peek (adapter, avail);
+ if (buf && (marker = gst_wavpack_parse_find_marker ((guint8 *) buf, avail))) {
+ gst_adapter_flush (adapter, marker - buf);
+ return TRUE;
+ }
+
+ /* flush everything except the last 4 bytes. they could contain
+ * the start of a new marker */
+ gst_adapter_flush (adapter, avail - 4);
+
+ return FALSE;
+}
+
+static GstFlowReturn
+gst_wavpack_parse_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstWavpackParse *wvparse = GST_WAVPACK_PARSE (GST_PAD_PARENT (pad));
+
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ WavpackHeader wph;
+
+ const guint8 *tmp_buf;
+
+ if (!wvparse->adapter) {
+ wvparse->adapter = gst_adapter_new ();
+ }
+
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ gst_adapter_clear (wvparse->adapter);
+ wvparse->discont = TRUE;
+ }
+
+ gst_adapter_push (wvparse->adapter, buf);
+
+ if (gst_adapter_available (wvparse->adapter) < sizeof (WavpackHeader))
+ return ret;
+
+ if (!gst_wavpack_parse_resync_adapter (wvparse->adapter))
+ return ret;
+
+ tmp_buf = gst_adapter_peek (wvparse->adapter, sizeof (WavpackHeader));
+ gst_wavpack_read_header (&wph, (guint8 *) tmp_buf);
+
+ while (gst_adapter_available (wvparse->adapter) >= wph.ckSize + 4 * 1 + 4) {
+ GstBuffer *outbuf =
+ gst_adapter_take_buffer (wvparse->adapter, wph.ckSize + 4 * 1 + 4);
+
+ if (!outbuf)
+ return GST_FLOW_ERROR;
+
+ if (wvparse->srcpad == NULL) {
+ if (!gst_wavpack_parse_create_src_pad (wvparse, outbuf, &wph)) {
+ GST_ERROR_OBJECT (wvparse, "Failed to create src pad");
+ ret = GST_FLOW_ERROR;
+ break;
+ }
+ }
+
+ ret = gst_wavpack_parse_push_buffer (wvparse, outbuf, &wph);
+
+ if (ret != GST_FLOW_OK)
+ break;
+
+ if (gst_adapter_available (wvparse->adapter) >= sizeof (WavpackHeader)) {
+ tmp_buf = gst_adapter_peek (wvparse->adapter, sizeof (WavpackHeader));
+
+ if (!gst_wavpack_parse_resync_adapter (wvparse->adapter))
+ break;
+
+ gst_wavpack_read_header (&wph, (guint8 *) tmp_buf);
+ }
+ }
+
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_wavpack_parse_change_state (GstElement * element, GstStateChange transition)
+{
+ GstWavpackParse *wvparse = GST_WAVPACK_PARSE (element);
+
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_segment_init (&wvparse->segment, GST_FORMAT_DEFAULT);
+ wvparse->segment.last_stop = 0;
+ default:
+ break;
+ }
+
+ if (GST_ELEMENT_CLASS (parent_class)->change_state)
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_wavpack_parse_reset (wvparse);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_wavpack_parse_sink_activate (GstPad * sinkpad)
+{
+ if (gst_pad_check_pull_range (sinkpad)) {
+ return gst_pad_activate_pull (sinkpad, TRUE);
+ } else {
+ return gst_pad_activate_push (sinkpad, TRUE);
+ }
+}
+
+static gboolean
+gst_wavpack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active)
+{
+ gboolean result;
+
+ if (active) {
+ result = gst_pad_start_task (sinkpad,
+ (GstTaskFunction) gst_wavpack_parse_loop, GST_PAD_PARENT (sinkpad));
+ } else {
+ result = gst_pad_stop_task (sinkpad);
+ }
+
+ return result;
+}
+
+gboolean
+gst_wavpack_parse_plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "wavpackparse",
+ GST_RANK_PRIMARY, GST_TYPE_WAVPACK_PARSE)) {
+ return FALSE;
+ }
+
+ GST_DEBUG_CATEGORY_INIT (gst_wavpack_parse_debug, "wavpack_parse", 0,
+ "Wavpack file parser");
+
+ return TRUE;
+}
diff --git a/ext/wavpack/gstwavpackparse.h b/ext/wavpack/gstwavpackparse.h
new file mode 100644
index 0000000..60504a7
--- /dev/null
+++ b/ext/wavpack/gstwavpackparse.h
@@ -0,0 +1,97 @@
+/* GStreamer wavpack plugin
+ * (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
+ *
+ * gstwavpackparse.h: wavpack file parser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_WAVPACK_PARSE_H__
+#define __GST_WAVPACK_PARSE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_WAVPACK_PARSE \
+ (gst_wavpack_parse_get_type())
+#define GST_WAVPACK_PARSE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVPACK_PARSE,GstWavpackParse))
+#define GST_WAVPACK_PARSE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVPACK_PARSE,GstWavpackParseClass))
+#define GST_IS_WAVPACK_PARSE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVPACK_PARSE))
+#define GST_IS_WAVPACK_PARSE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVPACK_PARSE))
+typedef struct _GstWavpackParse GstWavpackParse;
+typedef struct _GstWavpackParseClass GstWavpackParseClass;
+typedef struct _GstWavpackParseIndexEntry GstWavpackParseIndexEntry;
+
+struct _GstWavpackParseIndexEntry
+{
+ gint64 byte_offset; /* byte offset of this chunk */
+ gint64 sample_offset; /* first sample in this chunk */
+ gint64 sample_offset_end; /* first sample in next chunk */
+};
+
+struct _GstWavpackParse
+{
+ GstElement element;
+
+ /*< private > */
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ guint samplerate;
+ guint channels;
+ gint64 total_samples;
+
+ gboolean need_newsegment;
+ gboolean discont;
+
+ gint64 current_offset; /* byte offset on sink pad */
+ gint64 upstream_length; /* length of file in bytes */
+
+ GstSegment segment; /* the currently configured segment, in
+ * samples/audio frames (DEFAULT format) */
+
+ GstBuffer *pending_buffer;
+ gint32 pending_offset;
+ guint32 next_block_index;
+
+ GstAdapter *adapter; /* when operating chain-based, otherwise NULL */
+
+ /* List of GstWavpackParseIndexEntry structs, mapping known
+ * sample offsets to byte offsets. Is kept increasing without
+ * gaps (ie. append only and consecutive entries must always
+ * map to consecutive chunks in the file). */
+ GSList *entries;
+
+ /* Queued events (e.g. tag events we receive before we create the src pad) */
+ GList *queued_events; /* STREAM_LOCK */
+};
+
+struct _GstWavpackParseClass
+{
+ GstElementClass parent;
+};
+
+GType gst_wavpack_parse_get_type (void);
+
+gboolean gst_wavpack_parse_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_WAVPACK_PARSE_H__ */
diff --git a/ext/wavpack/gstwavpackstreamreader.c b/ext/wavpack/gstwavpackstreamreader.c
new file mode 100644
index 0000000..074a2e7
--- /dev/null
+++ b/ext/wavpack/gstwavpackstreamreader.c
@@ -0,0 +1,124 @@
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackstreamreader.c: stream reader used for decoding
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <math.h>
+#include <gst/gst.h>
+
+#include "gstwavpackstreamreader.h"
+
+GST_DEBUG_CATEGORY_EXTERN (wavpack_debug);
+#define GST_CAT_DEFAULT wavpack_debug
+
+static int32_t
+gst_wavpack_stream_reader_read_bytes (void *id, void *data, int32_t bcount)
+{
+ read_id *rid = (read_id *) id;
+ uint32_t left = rid->length - rid->position;
+ uint32_t to_read = MIN (left, bcount);
+
+ GST_DEBUG ("Trying to read %d of %d bytes from position %d", bcount,
+ rid->length, rid->position);
+
+ if (to_read > 0) {
+ g_memmove (data, rid->buffer + rid->position, to_read);
+ rid->position += to_read;
+ return to_read;
+ } else {
+ GST_WARNING ("Couldn't read %d bytes", bcount);
+ return 0;
+ }
+}
+
+static uint32_t
+gst_wavpack_stream_reader_get_pos (void *id)
+{
+ GST_DEBUG ("Returning position %d", ((read_id *) id)->position);
+ return ((read_id *) id)->position;
+}
+
+static int
+gst_wavpack_stream_reader_set_pos_abs (void *id, uint32_t pos)
+{
+ GST_WARNING ("Should not be called: tried to set absolute position to %d",
+ pos);
+ return -1;
+}
+
+static int
+gst_wavpack_stream_reader_set_pos_rel (void *id, int32_t delta, int mode)
+{
+ GST_WARNING ("Should not be called: tried to set relative position to %d"
+ " with mode %d", delta, mode);
+ return -1;
+}
+
+static int
+gst_wavpack_stream_reader_push_back_byte (void *id, int c)
+{
+ read_id *rid = (read_id *) id;
+
+ GST_DEBUG ("Pushing back one byte: 0x%x", c);
+
+ rid->position -= 1;
+ if (rid->position < 0)
+ rid->position = 0;
+ return rid->position;
+}
+
+static uint32_t
+gst_wavpack_stream_reader_get_length (void *id)
+{
+ GST_DEBUG ("Returning length %d", ((read_id *) id)->length);
+
+ return ((read_id *) id)->length;
+}
+
+static int
+gst_wavpack_stream_reader_can_seek (void *id)
+{
+ GST_DEBUG ("Can't seek");
+ return FALSE;
+}
+
+static int32_t
+gst_wavpack_stream_reader_write_bytes (void *id, void *data, int32_t bcount)
+{
+ GST_WARNING ("Should not be called, tried to write %d bytes", bcount);
+ return 0;
+}
+
+WavpackStreamReader *
+gst_wavpack_stream_reader_new (void)
+{
+ WavpackStreamReader *stream_reader =
+ (WavpackStreamReader *) g_malloc0 (sizeof (WavpackStreamReader));
+ stream_reader->read_bytes = gst_wavpack_stream_reader_read_bytes;
+ stream_reader->get_pos = gst_wavpack_stream_reader_get_pos;
+ stream_reader->set_pos_abs = gst_wavpack_stream_reader_set_pos_abs;
+ stream_reader->set_pos_rel = gst_wavpack_stream_reader_set_pos_rel;
+ stream_reader->push_back_byte = gst_wavpack_stream_reader_push_back_byte;
+ stream_reader->get_length = gst_wavpack_stream_reader_get_length;
+ stream_reader->can_seek = gst_wavpack_stream_reader_can_seek;
+ stream_reader->write_bytes = gst_wavpack_stream_reader_write_bytes;
+
+ return stream_reader;
+}
diff --git a/ext/wavpack/gstwavpackstreamreader.h b/ext/wavpack/gstwavpackstreamreader.h
new file mode 100644
index 0000000..713b4c1
--- /dev/null
+++ b/ext/wavpack/gstwavpackstreamreader.h
@@ -0,0 +1,36 @@
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackstreamreader.h: stream reader used for decoding
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_WAVPACK_STREAM_READER_H__
+#define __GST_WAVPACK_STREAM_READER_H__
+
+#include <wavpack/wavpack.h>
+
+typedef struct
+{
+ guint8 *buffer;
+ uint32_t length;
+ uint32_t position;
+} read_id;
+
+WavpackStreamReader *gst_wavpack_stream_reader_new (void);
+
+#endif