diff options
author | HyungKyu Song <hk76.song@samsung.com> | 2013-02-16 00:14:42 +0900 |
---|---|---|
committer | HyungKyu Song <hk76.song@samsung.com> | 2013-02-16 00:14:42 +0900 |
commit | 715f9ce62a12d128754d2cf47f90a024b537e320 (patch) | |
tree | 57fb94c81055a31938bea831641092152a03089f /ext | |
parent | dfa84b358c7cdf0535eba1fead62fc4122cc56e6 (diff) | |
download | gst-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')
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 <gst/gst.h> + * #include <gst/video/video.h> + * + * ... + * + * 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, &state->width, &state->height); + * state->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->valid) + * return; + * + * scale = 2*(((timestamp/(int)1e7) % 70)+30)/100.0; + * cairo_translate(cr, s->width/2, (s->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 ("cairooverlay", "overlay"); + * + * g_signal_connect (cairo_overlay, "draw", G_CALLBACK (draw_overlay), + * overlay_state); + * g_signal_connect (cairo_overlay, "caps-changed", + * 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>"preroll-pixbuf" + * </classname> or <classname>"pixbuf"</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>"preroll-pixbuf" + * </classname> or <classname>"pixbuf"</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>"pixbuf"</classname>: the #GdkPixbuf object + * </listitem> + * <listitem> + * <classname>"pixel-aspect-ratio"</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 '(NULL)'). + * </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_<name>_<num> where + * <name> is the element name and <num> 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_<name>_<num> where + * <name> is the element name and <num> 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, ×tamp); + 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, + ¶ms)) != 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> /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, ©right); + + 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> /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 |