diff options
Diffstat (limited to 'sys')
112 files changed, 38769 insertions, 0 deletions
diff --git a/sys/Makefile.am b/sys/Makefile.am new file mode 100644 index 0000000..ab08d04 --- /dev/null +++ b/sys/Makefile.am @@ -0,0 +1,84 @@ +# if USE_DXR3 +# DXR3_DIR=dxr3 +# else +# DXR3_DIR= +# endif + +if USE_OSS +OSS_DIR=oss +else +OSS_DIR= +endif + +if USE_OSS4 +OSS4_DIR=oss4 +else +OSS4_DIR= +endif + + +if USE_DIRECTSOUND +DIRECTSOUND_DIR=directsound +else +DIRECTSOUND_DIR= +endif + +if USE_SUNAUDIO +SUNAUDIO_DIR=sunaudio +else +SUNAUDIO_DIR= +endif + +if USE_OSX_AUDIO +OSX_AUDIO_DIR=osxaudio +else +OSX_AUDIO_DIR= +endif + +if USE_OSX_VIDEO +OSX_VIDEO_DIR=osxvideo +else +OSX_VIDEO_DIR= +endif + +# if USE_QCAM +# QCAM_DIR=qcam +# else +# QCAM_DIR= +# endif + +if USE_GST_V4L2 +V4L2_DIR=v4l2 +else +V4L2_DIR= +endif + +# if USE_VCD +# VCD_DIR=vcd +# else +# VCD_DIR= +# endif + +# if USE_CDROM +# CDROM_DIR=cdrom +# else +# CDROM_DIR= +# endif + +# if USE_OPENGL +# GL_DIR=glsink +# else +# GL_DIR= +# endif + +if USE_X +XIMAGE_DIR=ximage +else +XIMAGE_DIR= +endif + +SUBDIRS=$(DIRECTSOUND_DIR) $(OSS_DIR) $(OSS4_DIR) $(OSX_AUDIO_DIR) $(OSX_VIDEO_DIR) $(SUNAUDIO_DIR) $(V4L2_DIR) $(XIMAGE_DIR) + +DIST_SUBDIRS=directsound oss oss4 osxaudio osxvideo sunaudio v4l2 waveform ximage + +include $(top_srcdir)/common/parallel-subdirs.mak diff --git a/sys/Makefile.in b/sys/Makefile.in new file mode 100644 index 0000000..c37f1df --- /dev/null +++ b/sys/Makefile.in @@ -0,0 +1,869 @@ +# 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@ + +# if USE_DXR3 +# DXR3_DIR=dxr3 +# else +# DXR3_DIR= +# endif + +# 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 = sys +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_OSS_FALSE@OSS_DIR = +@USE_OSS_TRUE@OSS_DIR = oss +@USE_OSS4_FALSE@OSS4_DIR = +@USE_OSS4_TRUE@OSS4_DIR = oss4 +@USE_DIRECTSOUND_FALSE@DIRECTSOUND_DIR = +@USE_DIRECTSOUND_TRUE@DIRECTSOUND_DIR = directsound +@USE_SUNAUDIO_FALSE@SUNAUDIO_DIR = +@USE_SUNAUDIO_TRUE@SUNAUDIO_DIR = sunaudio +@USE_OSX_AUDIO_FALSE@OSX_AUDIO_DIR = +@USE_OSX_AUDIO_TRUE@OSX_AUDIO_DIR = osxaudio +@USE_OSX_VIDEO_FALSE@OSX_VIDEO_DIR = +@USE_OSX_VIDEO_TRUE@OSX_VIDEO_DIR = osxvideo +@USE_GST_V4L2_FALSE@V4L2_DIR = + +# if USE_QCAM +# QCAM_DIR=qcam +# else +# QCAM_DIR= +# endif +@USE_GST_V4L2_TRUE@V4L2_DIR = v4l2 +@USE_X_FALSE@XIMAGE_DIR = + +# if USE_VCD +# VCD_DIR=vcd +# else +# VCD_DIR= +# endif + +# if USE_CDROM +# CDROM_DIR=cdrom +# else +# CDROM_DIR= +# endif + +# if USE_OPENGL +# GL_DIR=glsink +# else +# GL_DIR= +# endif +@USE_X_TRUE@XIMAGE_DIR = ximage +SUBDIRS = $(DIRECTSOUND_DIR) $(OSS_DIR) $(OSS4_DIR) $(OSX_AUDIO_DIR) $(OSX_VIDEO_DIR) $(SUNAUDIO_DIR) $(V4L2_DIR) $(XIMAGE_DIR) +DIST_SUBDIRS = directsound oss oss4 osxaudio osxvideo sunaudio v4l2 waveform ximage +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 sys/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu sys/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/sys/directsound/Makefile.am b/sys/directsound/Makefile.am new file mode 100644 index 0000000..8227905 --- /dev/null +++ b/sys/directsound/Makefile.am @@ -0,0 +1,18 @@ +plugin_LTLIBRARIES = libgstdirectsoundsink.la
+
+libgstdirectsoundsink_la_SOURCES = gstdirectsoundsink.c gstdirectsoundplugin.c
+libgstdirectsoundsink_la_CFLAGS = \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) \ + $(DIRECTSOUND_CFLAGS) +libgstdirectsoundsink_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstaudio-$(GST_MAJORMINOR) -lgstinterfaces-$(GST_MAJORMINOR) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) \ + $(DIRECTSOUND_LIBS) +libgstdirectsoundsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(DIRECTSOUND_LDFLAGS)
+libgstdirectsoundsink_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstdirectsoundsink.h diff --git a/sys/directsound/Makefile.in b/sys/directsound/Makefile.in new file mode 100644 index 0000000..94cbb01 --- /dev/null +++ b/sys/directsound/Makefile.in @@ -0,0 +1,828 @@ +# 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 = sys/directsound +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 = +libgstdirectsoundsink_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_libgstdirectsoundsink_la_OBJECTS = \ + libgstdirectsoundsink_la-gstdirectsoundsink.lo \ + libgstdirectsoundsink_la-gstdirectsoundplugin.lo +libgstdirectsoundsink_la_OBJECTS = \ + $(am_libgstdirectsoundsink_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +libgstdirectsoundsink_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(libgstdirectsoundsink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(libgstdirectsoundsink_la_CFLAGS) \ + $(CFLAGS) $(libgstdirectsoundsink_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 = $(libgstdirectsoundsink_la_SOURCES) +DIST_SOURCES = $(libgstdirectsoundsink_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 = libgstdirectsoundsink.la +libgstdirectsoundsink_la_SOURCES = gstdirectsoundsink.c gstdirectsoundplugin.c +libgstdirectsoundsink_la_CFLAGS = \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) \ + $(DIRECTSOUND_CFLAGS) + +libgstdirectsoundsink_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstaudio-$(GST_MAJORMINOR) -lgstinterfaces-$(GST_MAJORMINOR) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) \ + $(DIRECTSOUND_LIBS) + +libgstdirectsoundsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(DIRECTSOUND_LDFLAGS) +libgstdirectsoundsink_la_LIBTOOLFLAGS = --tag=disable-static +noinst_HEADERS = gstdirectsoundsink.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 sys/directsound/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu sys/directsound/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 +libgstdirectsoundsink.la: $(libgstdirectsoundsink_la_OBJECTS) $(libgstdirectsoundsink_la_DEPENDENCIES) $(EXTRA_libgstdirectsoundsink_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgstdirectsoundsink_la_LINK) -rpath $(plugindir) $(libgstdirectsoundsink_la_OBJECTS) $(libgstdirectsoundsink_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstdirectsoundsink_la-gstdirectsoundplugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstdirectsoundsink_la-gstdirectsoundsink.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 $@ $< + +libgstdirectsoundsink_la-gstdirectsoundsink.lo: gstdirectsoundsink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdirectsoundsink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdirectsoundsink_la_CFLAGS) $(CFLAGS) -MT libgstdirectsoundsink_la-gstdirectsoundsink.lo -MD -MP -MF $(DEPDIR)/libgstdirectsoundsink_la-gstdirectsoundsink.Tpo -c -o libgstdirectsoundsink_la-gstdirectsoundsink.lo `test -f 'gstdirectsoundsink.c' || echo '$(srcdir)/'`gstdirectsoundsink.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstdirectsoundsink_la-gstdirectsoundsink.Tpo $(DEPDIR)/libgstdirectsoundsink_la-gstdirectsoundsink.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstdirectsoundsink.c' object='libgstdirectsoundsink_la-gstdirectsoundsink.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 $(libgstdirectsoundsink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdirectsoundsink_la_CFLAGS) $(CFLAGS) -c -o libgstdirectsoundsink_la-gstdirectsoundsink.lo `test -f 'gstdirectsoundsink.c' || echo '$(srcdir)/'`gstdirectsoundsink.c + +libgstdirectsoundsink_la-gstdirectsoundplugin.lo: gstdirectsoundplugin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstdirectsoundsink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdirectsoundsink_la_CFLAGS) $(CFLAGS) -MT libgstdirectsoundsink_la-gstdirectsoundplugin.lo -MD -MP -MF $(DEPDIR)/libgstdirectsoundsink_la-gstdirectsoundplugin.Tpo -c -o libgstdirectsoundsink_la-gstdirectsoundplugin.lo `test -f 'gstdirectsoundplugin.c' || echo '$(srcdir)/'`gstdirectsoundplugin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstdirectsoundsink_la-gstdirectsoundplugin.Tpo $(DEPDIR)/libgstdirectsoundsink_la-gstdirectsoundplugin.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstdirectsoundplugin.c' object='libgstdirectsoundsink_la-gstdirectsoundplugin.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 $(libgstdirectsoundsink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstdirectsoundsink_la_CFLAGS) $(CFLAGS) -c -o libgstdirectsoundsink_la-gstdirectsoundplugin.lo `test -f 'gstdirectsoundplugin.c' || echo '$(srcdir)/'`gstdirectsoundplugin.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/sys/directsound/gstdirectsoundplugin.c b/sys/directsound/gstdirectsoundplugin.c new file mode 100644 index 0000000..1af665a --- /dev/null +++ b/sys/directsound/gstdirectsoundplugin.c @@ -0,0 +1,49 @@ +/* GStreamer +* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net> +* Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com> +* +* gstdirectsoundplugin.c: +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public +* License along with this library; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 02111-1307, USA. +* +* +* The development of this code was made possible due to the involvement +* of Pioneers of the Inevitable, the creators of the Songbird Music player +* +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstdirectsoundsink.h" + + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "directsoundsink", GST_RANK_PRIMARY, + GST_TYPE_DIRECTSOUND_SINK)) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "directsound", + "Direct Sound plugin library", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/directsound/gstdirectsoundsink.c b/sys/directsound/gstdirectsoundsink.c new file mode 100644 index 0000000..2f9a04c --- /dev/null +++ b/sys/directsound/gstdirectsoundsink.c @@ -0,0 +1,785 @@ +/* GStreamer +* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net> +* Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com> +* Copyright (C) 2010 Fluendo S.A. <support@fluendo.com> +* +* gstdirectsoundsink.c: +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public +* License along with this library; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 02111-1307, USA. +* +* +* The development of this code was made possible due to the involvement +* of Pioneers of the Inevitable, the creators of the Songbird Music player +* +*/ + +/** + * SECTION:element-directsoundsink + * + * This element lets you output sound using the DirectSound API. + * + * Note that you should almost always use generic audio conversion elements + * like audioconvert and audioresample in front of an audiosink to make sure + * your pipeline works under all circumstances (those conversion elements will + * act in passthrough-mode if no conversion is necessary). + * + * <refsect2> + * <title>Example pipelines</title> + * |[ + * gst-launch -v audiotestsrc ! audioconvert ! volume volume=0.1 ! directsoundsink + * ]| will output a sine wave (continuous beep sound) to your sound card (with + * a very low volume as precaution). + * |[ + * gst-launch -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! directsoundsink + * ]| will play an Ogg/Vorbis audio file and output it. + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstdirectsoundsink.h" + +#include <math.h> + +#ifdef __CYGWIN__ +#include <unistd.h> +#ifndef _swab +#define _swab swab +#endif +#endif + +GST_DEBUG_CATEGORY_STATIC (directsoundsink_debug); +#define GST_CAT_DEFAULT directsoundsink_debug + +static void gst_directsound_sink_finalise (GObject * object); + +static void gst_directsound_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_directsound_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstCaps *gst_directsound_sink_getcaps (GstBaseSink * bsink); +static gboolean gst_directsound_sink_prepare (GstAudioSink * asink, + GstRingBufferSpec * spec); +static gboolean gst_directsound_sink_unprepare (GstAudioSink * asink); + +static gboolean gst_directsound_sink_open (GstAudioSink * asink); +static gboolean gst_directsound_sink_close (GstAudioSink * asink); +static guint gst_directsound_sink_write (GstAudioSink * asink, gpointer data, + guint length); +static guint gst_directsound_sink_delay (GstAudioSink * asink); +static void gst_directsound_sink_reset (GstAudioSink * asink); +static GstCaps *gst_directsound_probe_supported_formats (GstDirectSoundSink * + dsoundsink, const GstCaps * template_caps); + +/* interfaces */ +static void gst_directsound_sink_interfaces_init (GType type); +static void +gst_directsound_sink_implements_interface_init (GstImplementsInterfaceClass * + iface); +static void gst_directsound_sink_mixer_interface_init (GstMixerClass * iface); + +static GstStaticPadTemplate directsoundsink_sink_factory = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "signed = (boolean) TRUE, " + "width = (int) 16, " + "depth = (int) 16, " + "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; " + "audio/x-raw-int, " + "signed = (boolean) FALSE, " + "width = (int) 8, " + "depth = (int) 8, " + "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ];" + "audio/x-iec958")); + +enum +{ + PROP_0, + PROP_VOLUME +}; + +GST_BOILERPLATE_FULL (GstDirectSoundSink, gst_directsound_sink, GstAudioSink, + GST_TYPE_AUDIO_SINK, gst_directsound_sink_interfaces_init); + +/* interfaces stuff */ +static void +gst_directsound_sink_interfaces_init (GType type) +{ + static const GInterfaceInfo implements_interface_info = { + (GInterfaceInitFunc) gst_directsound_sink_implements_interface_init, + NULL, + NULL, + }; + + static const GInterfaceInfo mixer_interface_info = { + (GInterfaceInitFunc) gst_directsound_sink_mixer_interface_init, + NULL, + NULL, + }; + + g_type_add_interface_static (type, + GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info); + g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_interface_info); +} + +static gboolean +gst_directsound_sink_interface_supported (GstImplementsInterface * iface, + GType iface_type) +{ + g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE); + + /* for the sake of this example, we'll always support it. However, normally, + * you would check whether the device you've opened supports mixers. */ + return TRUE; +} + +static void +gst_directsound_sink_implements_interface_init (GstImplementsInterfaceClass * + iface) +{ + iface->supported = gst_directsound_sink_interface_supported; +} + +/* + * This function returns the list of support tracks (inputs, outputs) + * on this element instance. Elements usually build this list during + * _init () or when going from NULL to READY. + */ + +static const GList * +gst_directsound_sink_mixer_list_tracks (GstMixer * mixer) +{ + GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (mixer); + + return dsoundsink->tracks; +} + +static void +gst_directsound_sink_set_volume (GstDirectSoundSink * dsoundsink) +{ + if (dsoundsink->pDSBSecondary) { + /* DirectSound controls volume using units of 100th of a decibel, + * ranging from -10000 to 0. We use a linear scale of 0 - 100 + * here, so remap. + */ + long dsVolume; + if (dsoundsink->volume == 0) + dsVolume = -10000; + else + dsVolume = 100 * (long) (20 * log10 ((double) dsoundsink->volume / 100.)); + dsVolume = CLAMP (dsVolume, -10000, 0); + + GST_DEBUG_OBJECT (dsoundsink, + "Setting volume on secondary buffer to %d from %d", (int) dsVolume, + (int) dsoundsink->volume); + IDirectSoundBuffer_SetVolume (dsoundsink->pDSBSecondary, dsVolume); + } +} + +/* + * Set volume. volumes is an array of size track->num_channels, and + * each value in the array gives the wanted volume for one channel + * on the track. + */ + +static void +gst_directsound_sink_mixer_set_volume (GstMixer * mixer, + GstMixerTrack * track, gint * volumes) +{ + GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (mixer); + + if (volumes[0] != dsoundsink->volume) { + dsoundsink->volume = volumes[0]; + + gst_directsound_sink_set_volume (dsoundsink); + } +} + +static void +gst_directsound_sink_mixer_get_volume (GstMixer * mixer, + GstMixerTrack * track, gint * volumes) +{ + GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (mixer); + + volumes[0] = dsoundsink->volume; +} + +static void +gst_directsound_sink_mixer_interface_init (GstMixerClass * iface) +{ + /* the mixer interface requires a definition of the mixer type: + * hardware or software? */ + GST_MIXER_TYPE (iface) = GST_MIXER_SOFTWARE; + + /* virtual function pointers */ + iface->list_tracks = gst_directsound_sink_mixer_list_tracks; + iface->set_volume = gst_directsound_sink_mixer_set_volume; + iface->get_volume = gst_directsound_sink_mixer_get_volume; +} + +static void +gst_directsound_sink_finalise (GObject * object) +{ + GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (object); + + g_mutex_free (dsoundsink->dsound_lock); + + if (dsoundsink->tracks) { + g_list_foreach (dsoundsink->tracks, (GFunc) g_object_unref, NULL); + g_list_free (dsoundsink->tracks); + dsoundsink->tracks = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_directsound_sink_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details_simple (element_class, + "Direct Sound Audio Sink", "Sink/Audio", + "Output to a sound card via Direct Sound", + "Sebastien Moutte <sebastien@moutte.net>"); + gst_element_class_add_static_pad_template (element_class, + &directsoundsink_sink_factory); +} + +static void +gst_directsound_sink_class_init (GstDirectSoundSinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *gstbasesink_class; + GstBaseAudioSinkClass *gstbaseaudiosink_class; + GstAudioSinkClass *gstaudiosink_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesink_class = (GstBaseSinkClass *) klass; + gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass; + gstaudiosink_class = (GstAudioSinkClass *) klass; + + GST_DEBUG_CATEGORY_INIT (directsoundsink_debug, "directsoundsink", 0, + "DirectSound sink"); + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->finalize = gst_directsound_sink_finalise; + gobject_class->set_property = gst_directsound_sink_set_property; + gobject_class->get_property = gst_directsound_sink_get_property; + + gstbasesink_class->get_caps = + GST_DEBUG_FUNCPTR (gst_directsound_sink_getcaps); + + gstaudiosink_class->prepare = + GST_DEBUG_FUNCPTR (gst_directsound_sink_prepare); + gstaudiosink_class->unprepare = + GST_DEBUG_FUNCPTR (gst_directsound_sink_unprepare); + gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_directsound_sink_open); + gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_directsound_sink_close); + gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_directsound_sink_write); + gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_directsound_sink_delay); + gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_directsound_sink_reset); + + g_object_class_install_property (gobject_class, + PROP_VOLUME, + g_param_spec_double ("volume", "Volume", + "Volume of this stream", 0.0, 1.0, 1.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +static void +gst_directsound_sink_init (GstDirectSoundSink * dsoundsink, + GstDirectSoundSinkClass * g_class) +{ + GstMixerTrack *track = NULL; + + dsoundsink->tracks = NULL; + track = g_object_new (GST_TYPE_MIXER_TRACK, NULL); + track->label = g_strdup ("DSoundTrack"); + track->num_channels = 2; + track->min_volume = 0; + track->max_volume = 100; + track->flags = GST_MIXER_TRACK_OUTPUT; + dsoundsink->tracks = g_list_append (dsoundsink->tracks, track); + + dsoundsink->pDS = NULL; + dsoundsink->cached_caps = NULL; + dsoundsink->pDSBSecondary = NULL; + dsoundsink->current_circular_offset = 0; + dsoundsink->buffer_size = DSBSIZE_MIN; + dsoundsink->volume = 100; + dsoundsink->dsound_lock = g_mutex_new (); + dsoundsink->first_buffer_after_reset = FALSE; +} + +static void +gst_directsound_sink_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstDirectSoundSink *sink = GST_DIRECTSOUND_SINK (object); + + switch (prop_id) { + case PROP_VOLUME: + sink->volume = (int) (g_value_get_double (value) * 100); + gst_directsound_sink_set_volume (sink); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_directsound_sink_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstDirectSoundSink *sink = GST_DIRECTSOUND_SINK (object); + + switch (prop_id) { + case PROP_VOLUME: + g_value_set_double (value, (double) sink->volume / 100.); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstCaps * +gst_directsound_sink_getcaps (GstBaseSink * bsink) +{ + GstElementClass *element_class; + GstPadTemplate *pad_template; + GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (bsink); + GstCaps *caps; + gchar *caps_string = NULL; + + if (dsoundsink->pDS == NULL) { + GST_DEBUG_OBJECT (dsoundsink, "device not open, using template caps"); + return NULL; /* base class will get template caps for us */ + } + + if (dsoundsink->cached_caps) { + caps_string = gst_caps_to_string (dsoundsink->cached_caps); + GST_DEBUG_OBJECT (dsoundsink, "Returning cached caps: %s", caps_string); + g_free (caps_string); + return gst_caps_ref (dsoundsink->cached_caps); + } + + element_class = GST_ELEMENT_GET_CLASS (dsoundsink); + pad_template = gst_element_class_get_pad_template (element_class, "sink"); + g_return_val_if_fail (pad_template != NULL, NULL); + + caps = gst_directsound_probe_supported_formats (dsoundsink, + gst_pad_template_get_caps (pad_template)); + if (caps) { + dsoundsink->cached_caps = gst_caps_ref (caps); + } + + if (caps) { + gchar *caps_string = gst_caps_to_string (caps); + GST_DEBUG_OBJECT (dsoundsink, "returning caps %s", caps_string); + g_free (caps_string); + } + + return caps; +} + +static gboolean +gst_directsound_sink_open (GstAudioSink * asink) +{ + GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (asink); + HRESULT hRes; + + /* create and initialize a DirecSound object */ + if (FAILED (hRes = DirectSoundCreate (NULL, &dsoundsink->pDS, NULL))) { + GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ, + ("gst_directsound_sink_open: DirectSoundCreate: %s", + DXGetErrorString9 (hRes)), (NULL)); + return FALSE; + } + + if (FAILED (hRes = IDirectSound_SetCooperativeLevel (dsoundsink->pDS, + GetDesktopWindow (), DSSCL_PRIORITY))) { + GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ, + ("gst_directsound_sink_open: IDirectSound_SetCooperativeLevel: %s", + DXGetErrorString9 (hRes)), (NULL)); + return FALSE; + } + + return TRUE; +} + +static gboolean +gst_directsound_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) +{ + GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (asink); + HRESULT hRes; + DSBUFFERDESC descSecondary; + WAVEFORMATEX wfx; + + /*save number of bytes per sample and buffer format */ + dsoundsink->bytes_per_sample = spec->bytes_per_sample; + dsoundsink->buffer_format = spec->format; + + /* fill the WAVEFORMATEX structure with spec params */ + memset (&wfx, 0, sizeof (wfx)); + if (spec->format != GST_IEC958) { + wfx.cbSize = sizeof (wfx); + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = spec->channels; + wfx.nSamplesPerSec = spec->rate; + wfx.wBitsPerSample = (spec->bytes_per_sample * 8) / wfx.nChannels; + wfx.nBlockAlign = spec->bytes_per_sample; + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + + /* Create directsound buffer with size based on our configured + * buffer_size (which is 200 ms by default) */ + dsoundsink->buffer_size = + gst_util_uint64_scale_int (wfx.nAvgBytesPerSec, spec->buffer_time, + GST_MSECOND); + /* Make sure we make those numbers multiple of our sample size in bytes */ + dsoundsink->buffer_size += dsoundsink->buffer_size % spec->bytes_per_sample; + + spec->segsize = + gst_util_uint64_scale_int (wfx.nAvgBytesPerSec, spec->latency_time, + GST_MSECOND); + spec->segsize += spec->segsize % spec->bytes_per_sample; + spec->segtotal = dsoundsink->buffer_size / spec->segsize; + } else { +#ifdef WAVE_FORMAT_DOLBY_AC3_SPDIF + wfx.cbSize = 0; + wfx.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; + wfx.nChannels = 2; + wfx.nSamplesPerSec = spec->rate; + wfx.wBitsPerSample = 16; + wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + + spec->segsize = 6144; + spec->segtotal = 10; +#else + g_assert_not_reached (); +#endif + } + + // Make the final buffer size be an integer number of segments + dsoundsink->buffer_size = spec->segsize * spec->segtotal; + + GST_INFO_OBJECT (dsoundsink, + "GstRingBufferSpec->channels: %d, GstRingBufferSpec->rate: %d, GstRingBufferSpec->bytes_per_sample: %d\n" + "WAVEFORMATEX.nSamplesPerSec: %ld, WAVEFORMATEX.wBitsPerSample: %d, WAVEFORMATEX.nBlockAlign: %d, WAVEFORMATEX.nAvgBytesPerSec: %ld\n" + "Size of dsound circular buffer=>%d\n", spec->channels, spec->rate, + spec->bytes_per_sample, wfx.nSamplesPerSec, wfx.wBitsPerSample, + wfx.nBlockAlign, wfx.nAvgBytesPerSec, dsoundsink->buffer_size); + + /* create a secondary directsound buffer */ + memset (&descSecondary, 0, sizeof (DSBUFFERDESC)); + descSecondary.dwSize = sizeof (DSBUFFERDESC); + descSecondary.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS; + if (spec->format != GST_IEC958) + descSecondary.dwFlags |= DSBCAPS_CTRLVOLUME; + + descSecondary.dwBufferBytes = dsoundsink->buffer_size; + descSecondary.lpwfxFormat = (WAVEFORMATEX *) & wfx; + + hRes = IDirectSound_CreateSoundBuffer (dsoundsink->pDS, &descSecondary, + &dsoundsink->pDSBSecondary, NULL); + if (FAILED (hRes)) { + GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ, + ("gst_directsound_sink_prepare: IDirectSound_CreateSoundBuffer: %s", + DXGetErrorString9 (hRes)), (NULL)); + return FALSE; + } + + gst_directsound_sink_set_volume (dsoundsink); + + return TRUE; +} + +static gboolean +gst_directsound_sink_unprepare (GstAudioSink * asink) +{ + GstDirectSoundSink *dsoundsink; + + dsoundsink = GST_DIRECTSOUND_SINK (asink); + + /* release secondary DirectSound buffer */ + if (dsoundsink->pDSBSecondary) { + IDirectSoundBuffer_Release (dsoundsink->pDSBSecondary); + dsoundsink->pDSBSecondary = NULL; + } + + return TRUE; +} + +static gboolean +gst_directsound_sink_close (GstAudioSink * asink) +{ + GstDirectSoundSink *dsoundsink = NULL; + + dsoundsink = GST_DIRECTSOUND_SINK (asink); + + /* release DirectSound object */ + g_return_val_if_fail (dsoundsink->pDS != NULL, FALSE); + IDirectSound_Release (dsoundsink->pDS); + dsoundsink->pDS = NULL; + + gst_caps_replace (&dsoundsink->cached_caps, NULL); + + return TRUE; +} + +static guint +gst_directsound_sink_write (GstAudioSink * asink, gpointer data, guint length) +{ + GstDirectSoundSink *dsoundsink; + DWORD dwStatus; + HRESULT hRes; + LPVOID pLockedBuffer1 = NULL, pLockedBuffer2 = NULL; + DWORD dwSizeBuffer1, dwSizeBuffer2; + DWORD dwCurrentPlayCursor; + + dsoundsink = GST_DIRECTSOUND_SINK (asink); + + /* Fix endianness */ + if (dsoundsink->buffer_format == GST_IEC958) + _swab (data, data, length); + + GST_DSOUND_LOCK (dsoundsink); + + /* get current buffer status */ + hRes = IDirectSoundBuffer_GetStatus (dsoundsink->pDSBSecondary, &dwStatus); + + /* get current play cursor position */ + hRes = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary, + &dwCurrentPlayCursor, NULL); + + if (SUCCEEDED (hRes) && (dwStatus & DSBSTATUS_PLAYING)) { + DWORD dwFreeBufferSize; + + calculate_freesize: + /* calculate the free size of the circular buffer */ + if (dwCurrentPlayCursor < dsoundsink->current_circular_offset) + dwFreeBufferSize = + dsoundsink->buffer_size - (dsoundsink->current_circular_offset - + dwCurrentPlayCursor); + else + dwFreeBufferSize = + dwCurrentPlayCursor - dsoundsink->current_circular_offset; + + if (length >= dwFreeBufferSize) { + Sleep (100); + hRes = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary, + &dwCurrentPlayCursor, NULL); + + hRes = + IDirectSoundBuffer_GetStatus (dsoundsink->pDSBSecondary, &dwStatus); + if (SUCCEEDED (hRes) && (dwStatus & DSBSTATUS_PLAYING)) + goto calculate_freesize; + else { + dsoundsink->first_buffer_after_reset = FALSE; + GST_DSOUND_UNLOCK (dsoundsink); + return 0; + } + } + } + + if (dwStatus & DSBSTATUS_BUFFERLOST) { + hRes = IDirectSoundBuffer_Restore (dsoundsink->pDSBSecondary); /*need a loop waiting the buffer is restored?? */ + + dsoundsink->current_circular_offset = 0; + } + + hRes = IDirectSoundBuffer_Lock (dsoundsink->pDSBSecondary, + dsoundsink->current_circular_offset, length, &pLockedBuffer1, + &dwSizeBuffer1, &pLockedBuffer2, &dwSizeBuffer2, 0L); + + if (SUCCEEDED (hRes)) { + // Write to pointers without reordering. + memcpy (pLockedBuffer1, data, dwSizeBuffer1); + if (pLockedBuffer2 != NULL) + memcpy (pLockedBuffer2, (LPBYTE) data + dwSizeBuffer1, dwSizeBuffer2); + + // Update where the buffer will lock (for next time) + dsoundsink->current_circular_offset += dwSizeBuffer1 + dwSizeBuffer2; + dsoundsink->current_circular_offset %= dsoundsink->buffer_size; /* Circular buffer */ + + hRes = IDirectSoundBuffer_Unlock (dsoundsink->pDSBSecondary, pLockedBuffer1, + dwSizeBuffer1, pLockedBuffer2, dwSizeBuffer2); + } + + /* if the buffer was not in playing state yet, call play on the buffer + except if this buffer is the fist after a reset (base class call reset and write a buffer when setting the sink to pause) */ + if (!(dwStatus & DSBSTATUS_PLAYING) && + dsoundsink->first_buffer_after_reset == FALSE) { + hRes = IDirectSoundBuffer_Play (dsoundsink->pDSBSecondary, 0, 0, + DSBPLAY_LOOPING); + } + + dsoundsink->first_buffer_after_reset = FALSE; + + GST_DSOUND_UNLOCK (dsoundsink); + + return length; +} + +static guint +gst_directsound_sink_delay (GstAudioSink * asink) +{ + GstDirectSoundSink *dsoundsink; + HRESULT hRes; + DWORD dwCurrentPlayCursor; + DWORD dwBytesInQueue = 0; + gint nNbSamplesInQueue = 0; + DWORD dwStatus; + + dsoundsink = GST_DIRECTSOUND_SINK (asink); + + /* get current buffer status */ + hRes = IDirectSoundBuffer_GetStatus (dsoundsink->pDSBSecondary, &dwStatus); + + if (dwStatus & DSBSTATUS_PLAYING) { + /*evaluate the number of samples in queue in the circular buffer */ + hRes = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary, + &dwCurrentPlayCursor, NULL); + + if (hRes == S_OK) { + if (dwCurrentPlayCursor < dsoundsink->current_circular_offset) + dwBytesInQueue = + dsoundsink->current_circular_offset - dwCurrentPlayCursor; + else + dwBytesInQueue = + dsoundsink->current_circular_offset + (dsoundsink->buffer_size - + dwCurrentPlayCursor); + + nNbSamplesInQueue = dwBytesInQueue / dsoundsink->bytes_per_sample; + } + } + + return nNbSamplesInQueue; +} + +static void +gst_directsound_sink_reset (GstAudioSink * asink) +{ + GstDirectSoundSink *dsoundsink; + LPVOID pLockedBuffer = NULL; + DWORD dwSizeBuffer = 0; + + dsoundsink = GST_DIRECTSOUND_SINK (asink); + + GST_DSOUND_LOCK (dsoundsink); + + if (dsoundsink->pDSBSecondary) { + /*stop playing */ + HRESULT hRes = IDirectSoundBuffer_Stop (dsoundsink->pDSBSecondary); + + /*reset position */ + hRes = IDirectSoundBuffer_SetCurrentPosition (dsoundsink->pDSBSecondary, 0); + dsoundsink->current_circular_offset = 0; + + /*reset the buffer */ + hRes = IDirectSoundBuffer_Lock (dsoundsink->pDSBSecondary, + dsoundsink->current_circular_offset, dsoundsink->buffer_size, + &pLockedBuffer, &dwSizeBuffer, NULL, NULL, 0L); + + if (SUCCEEDED (hRes)) { + memset (pLockedBuffer, 0, dwSizeBuffer); + + hRes = + IDirectSoundBuffer_Unlock (dsoundsink->pDSBSecondary, pLockedBuffer, + dwSizeBuffer, NULL, 0); + } + } + + dsoundsink->first_buffer_after_reset = TRUE; + + GST_DSOUND_UNLOCK (dsoundsink); +} + +/* + * gst_directsound_probe_supported_formats: + * + * Takes the template caps and returns the subset which is actually + * supported by this device. + * + */ + +static GstCaps * +gst_directsound_probe_supported_formats (GstDirectSoundSink * dsoundsink, + const GstCaps * template_caps) +{ + HRESULT hRes; + DSBUFFERDESC descSecondary; + WAVEFORMATEX wfx; + GstCaps *caps; + + caps = gst_caps_copy (template_caps); + + /* + * Check availability of digital output by trying to create an SPDIF buffer + */ + +#ifdef WAVE_FORMAT_DOLBY_AC3_SPDIF + /* fill the WAVEFORMATEX structure with some standard AC3 over SPDIF params */ + memset (&wfx, 0, sizeof (wfx)); + wfx.cbSize = 0; + wfx.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; + wfx.nChannels = 2; + wfx.nSamplesPerSec = 48000; + wfx.wBitsPerSample = 16; + wfx.nBlockAlign = 4; + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + + // create a secondary directsound buffer + memset (&descSecondary, 0, sizeof (DSBUFFERDESC)); + descSecondary.dwSize = sizeof (DSBUFFERDESC); + descSecondary.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS; + descSecondary.dwBufferBytes = 6144; + descSecondary.lpwfxFormat = &wfx; + + hRes = IDirectSound_CreateSoundBuffer (dsoundsink->pDS, &descSecondary, + &dsoundsink->pDSBSecondary, NULL); + if (FAILED (hRes)) { + GST_INFO_OBJECT (dsoundsink, "AC3 passthrough not supported " + "(IDirectSound_CreateSoundBuffer returned: %s)\n", + DXGetErrorString9 (hRes)); + caps = + gst_caps_subtract (caps, gst_caps_new_simple ("audio/x-iec958", NULL)); + } else { + GST_INFO_OBJECT (dsoundsink, "AC3 passthrough supported"); + hRes = IDirectSoundBuffer_Release (dsoundsink->pDSBSecondary); + if (FAILED (hRes)) { + GST_DEBUG_OBJECT (dsoundsink, + "(IDirectSoundBuffer_Release returned: %s)\n", + DXGetErrorString9 (hRes)); + } + } +#else + caps = gst_caps_subtract (caps, gst_caps_new_simple ("audio/x-iec958", NULL)); +#endif + + return caps; +} diff --git a/sys/directsound/gstdirectsoundsink.h b/sys/directsound/gstdirectsoundsink.h new file mode 100644 index 0000000..8bb10bf --- /dev/null +++ b/sys/directsound/gstdirectsoundsink.h @@ -0,0 +1,97 @@ +/* GStreamer + * Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net> + * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com> + * Copyright (C) 2010 Fluendo S.A. <support@fluendo.com> + * + * gstdirectsoundsink.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. + * + * The development of this code was made possible due to the involvement + * of Pioneers of the Inevitable, the creators of the Songbird Music player + * + * + */ + +#ifndef __GST_DIRECTSOUNDSINK_H__ +#define __GST_DIRECTSOUNDSINK_H__ + +#include <gst/gst.h> +#include <gst/audio/gstaudiosink.h> +#include <gst/interfaces/mixer.h> + +#include <windows.h> +#include <dxerr9.h> +#include <dsound.h> +#include <mmreg.h> +#include <ks.h> +#include <ksmedia.h> + +G_BEGIN_DECLS +#define GST_TYPE_DIRECTSOUND_SINK (gst_directsound_sink_get_type()) +#define GST_DIRECTSOUND_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DIRECTSOUND_SINK,GstDirectSoundSink)) +#define GST_DIRECTSOUND_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DIRECTSOUND_SINK,GstDirectSoundSinkClass)) +#define GST_IS_DIRECTSOUND_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DIRECTSOUND_SINK)) +#define GST_IS_DIRECTSOUND_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DIRECTSOUND_SINK)) +typedef struct _GstDirectSoundSink GstDirectSoundSink; +typedef struct _GstDirectSoundSinkClass GstDirectSoundSinkClass; + +#define GST_DSOUND_LOCK(obj) (g_mutex_lock (obj->dsound_lock)) +#define GST_DSOUND_UNLOCK(obj) (g_mutex_unlock (obj->dsound_lock)) + +struct _GstDirectSoundSink +{ + GstAudioSink sink; + + /* directsound object interface pointer */ + LPDIRECTSOUND pDS; + + /* directsound sound object interface pointer */ + LPDIRECTSOUNDBUFFER pDSBSecondary; + + /* directSound buffer size */ + guint buffer_size; + + /* offset of the circular buffer where we must write next */ + guint current_circular_offset; + + guint bytes_per_sample; + + /* current volume setup by mixer interface */ + glong volume; + + /* tracks list of our mixer interface implementation */ + GList *tracks; + + GstCaps *cached_caps; + + /* lock used to protect writes and resets */ + GMutex *dsound_lock; + + gboolean first_buffer_after_reset; + + GstBufferFormat buffer_format; +}; + +struct _GstDirectSoundSinkClass +{ + GstAudioSinkClass parent_class; +}; + +GType gst_directsound_sink_get_type (void); + +G_END_DECLS +#endif /* __GST_DIRECTSOUNDSINK_H__ */ diff --git a/sys/oss/Makefile.am b/sys/oss/Makefile.am new file mode 100644 index 0000000..c42dfea --- /dev/null +++ b/sys/oss/Makefile.am @@ -0,0 +1,28 @@ +plugin_LTLIBRARIES = libgstossaudio.la + +libgstossaudio_la_SOURCES = gstossaudio.c \ + gstosshelper.c \ + gstossmixer.c \ + gstossmixerelement.c \ + gstossmixertrack.c \ + gstosssink.c \ + gstosssrc.c + +libgstossaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) +libgstossaudio_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstinterfaces-$(GST_MAJORMINOR) \ + -lgstaudio-$(GST_MAJORMINOR) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) +libgstossaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstossaudio_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = common.h \ + gstosssink.h \ + gstosssrc.h \ + gstosshelper.h \ + gstossdmabuffer.h \ + gstossmixer.h \ + gstossmixerelement.h \ + gstossmixertrack.h diff --git a/sys/oss/Makefile.in b/sys/oss/Makefile.in new file mode 100644 index 0000000..ce15b09 --- /dev/null +++ b/sys/oss/Makefile.in @@ -0,0 +1,879 @@ +# 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 = sys/oss +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 = +libgstossaudio_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgstossaudio_la_OBJECTS = libgstossaudio_la-gstossaudio.lo \ + libgstossaudio_la-gstosshelper.lo \ + libgstossaudio_la-gstossmixer.lo \ + libgstossaudio_la-gstossmixerelement.lo \ + libgstossaudio_la-gstossmixertrack.lo \ + libgstossaudio_la-gstosssink.lo libgstossaudio_la-gstosssrc.lo +libgstossaudio_la_OBJECTS = $(am_libgstossaudio_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +libgstossaudio_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(libgstossaudio_la_CFLAGS) $(CFLAGS) \ + $(libgstossaudio_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 = $(libgstossaudio_la_SOURCES) +DIST_SOURCES = $(libgstossaudio_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 = libgstossaudio.la +libgstossaudio_la_SOURCES = gstossaudio.c \ + gstosshelper.c \ + gstossmixer.c \ + gstossmixerelement.c \ + gstossmixertrack.c \ + gstosssink.c \ + gstosssrc.c + +libgstossaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) +libgstossaudio_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstinterfaces-$(GST_MAJORMINOR) \ + -lgstaudio-$(GST_MAJORMINOR) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) + +libgstossaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstossaudio_la_LIBTOOLFLAGS = --tag=disable-static +noinst_HEADERS = common.h \ + gstosssink.h \ + gstosssrc.h \ + gstosshelper.h \ + gstossdmabuffer.h \ + gstossmixer.h \ + gstossmixerelement.h \ + gstossmixertrack.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 sys/oss/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu sys/oss/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 +libgstossaudio.la: $(libgstossaudio_la_OBJECTS) $(libgstossaudio_la_DEPENDENCIES) $(EXTRA_libgstossaudio_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgstossaudio_la_LINK) -rpath $(plugindir) $(libgstossaudio_la_OBJECTS) $(libgstossaudio_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstossaudio_la-gstossaudio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstossaudio_la-gstosshelper.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstossaudio_la-gstossmixer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstossaudio_la-gstossmixerelement.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstossaudio_la-gstossmixertrack.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstossaudio_la-gstosssink.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstossaudio_la-gstosssrc.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 $@ $< + +libgstossaudio_la-gstossaudio.lo: gstossaudio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -MT libgstossaudio_la-gstossaudio.lo -MD -MP -MF $(DEPDIR)/libgstossaudio_la-gstossaudio.Tpo -c -o libgstossaudio_la-gstossaudio.lo `test -f 'gstossaudio.c' || echo '$(srcdir)/'`gstossaudio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstossaudio_la-gstossaudio.Tpo $(DEPDIR)/libgstossaudio_la-gstossaudio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstossaudio.c' object='libgstossaudio_la-gstossaudio.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 $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -c -o libgstossaudio_la-gstossaudio.lo `test -f 'gstossaudio.c' || echo '$(srcdir)/'`gstossaudio.c + +libgstossaudio_la-gstosshelper.lo: gstosshelper.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -MT libgstossaudio_la-gstosshelper.lo -MD -MP -MF $(DEPDIR)/libgstossaudio_la-gstosshelper.Tpo -c -o libgstossaudio_la-gstosshelper.lo `test -f 'gstosshelper.c' || echo '$(srcdir)/'`gstosshelper.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstossaudio_la-gstosshelper.Tpo $(DEPDIR)/libgstossaudio_la-gstosshelper.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosshelper.c' object='libgstossaudio_la-gstosshelper.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 $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -c -o libgstossaudio_la-gstosshelper.lo `test -f 'gstosshelper.c' || echo '$(srcdir)/'`gstosshelper.c + +libgstossaudio_la-gstossmixer.lo: gstossmixer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -MT libgstossaudio_la-gstossmixer.lo -MD -MP -MF $(DEPDIR)/libgstossaudio_la-gstossmixer.Tpo -c -o libgstossaudio_la-gstossmixer.lo `test -f 'gstossmixer.c' || echo '$(srcdir)/'`gstossmixer.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstossaudio_la-gstossmixer.Tpo $(DEPDIR)/libgstossaudio_la-gstossmixer.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstossmixer.c' object='libgstossaudio_la-gstossmixer.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 $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -c -o libgstossaudio_la-gstossmixer.lo `test -f 'gstossmixer.c' || echo '$(srcdir)/'`gstossmixer.c + +libgstossaudio_la-gstossmixerelement.lo: gstossmixerelement.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -MT libgstossaudio_la-gstossmixerelement.lo -MD -MP -MF $(DEPDIR)/libgstossaudio_la-gstossmixerelement.Tpo -c -o libgstossaudio_la-gstossmixerelement.lo `test -f 'gstossmixerelement.c' || echo '$(srcdir)/'`gstossmixerelement.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstossaudio_la-gstossmixerelement.Tpo $(DEPDIR)/libgstossaudio_la-gstossmixerelement.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstossmixerelement.c' object='libgstossaudio_la-gstossmixerelement.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 $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -c -o libgstossaudio_la-gstossmixerelement.lo `test -f 'gstossmixerelement.c' || echo '$(srcdir)/'`gstossmixerelement.c + +libgstossaudio_la-gstossmixertrack.lo: gstossmixertrack.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -MT libgstossaudio_la-gstossmixertrack.lo -MD -MP -MF $(DEPDIR)/libgstossaudio_la-gstossmixertrack.Tpo -c -o libgstossaudio_la-gstossmixertrack.lo `test -f 'gstossmixertrack.c' || echo '$(srcdir)/'`gstossmixertrack.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstossaudio_la-gstossmixertrack.Tpo $(DEPDIR)/libgstossaudio_la-gstossmixertrack.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstossmixertrack.c' object='libgstossaudio_la-gstossmixertrack.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 $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -c -o libgstossaudio_la-gstossmixertrack.lo `test -f 'gstossmixertrack.c' || echo '$(srcdir)/'`gstossmixertrack.c + +libgstossaudio_la-gstosssink.lo: gstosssink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -MT libgstossaudio_la-gstosssink.lo -MD -MP -MF $(DEPDIR)/libgstossaudio_la-gstosssink.Tpo -c -o libgstossaudio_la-gstosssink.lo `test -f 'gstosssink.c' || echo '$(srcdir)/'`gstosssink.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstossaudio_la-gstosssink.Tpo $(DEPDIR)/libgstossaudio_la-gstosssink.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosssink.c' object='libgstossaudio_la-gstosssink.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 $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -c -o libgstossaudio_la-gstosssink.lo `test -f 'gstosssink.c' || echo '$(srcdir)/'`gstosssink.c + +libgstossaudio_la-gstosssrc.lo: gstosssrc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -MT libgstossaudio_la-gstosssrc.lo -MD -MP -MF $(DEPDIR)/libgstossaudio_la-gstosssrc.Tpo -c -o libgstossaudio_la-gstosssrc.lo `test -f 'gstosssrc.c' || echo '$(srcdir)/'`gstosssrc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstossaudio_la-gstosssrc.Tpo $(DEPDIR)/libgstossaudio_la-gstosssrc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosssrc.c' object='libgstossaudio_la-gstosssrc.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 $(libgstossaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstossaudio_la_CFLAGS) $(CFLAGS) -c -o libgstossaudio_la-gstosssrc.lo `test -f 'gstosssrc.c' || echo '$(srcdir)/'`gstosssrc.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/sys/oss/common.h b/sys/oss/common.h new file mode 100644 index 0000000..2445c3d --- /dev/null +++ b/sys/oss/common.h @@ -0,0 +1,43 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> + * 2000,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. + */ + +#define SET_PARAM(_oss, _name, _val, _detail) \ +G_STMT_START { \ + int _tmp = _val; \ + if (ioctl(_oss->fd, _name, &_tmp) == -1) { \ + GST_ELEMENT_ERROR (_oss, RESOURCE, SETTINGS,\ + (NULL), \ + ("Unable to set param " _detail ": %s", \ + g_strerror (errno))); \ + return FALSE; \ + } \ + GST_DEBUG_OBJECT(_oss, _detail " %d", _tmp); \ +} G_STMT_END + +#define GET_PARAM(_oss, _name, _val, _detail) \ +G_STMT_START { \ + if (ioctl(oss->fd, _name, _val) == -1) { \ + GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, \ + (NULL), \ + ("Unable to get param " _detail ": %s", \ + g_strerror (errno))); \ + return FALSE; \ + } \ +} G_STMT_END diff --git a/sys/oss/gstossaudio.c b/sys/oss/gstossaudio.c new file mode 100644 index 0000000..2a181e8 --- /dev/null +++ b/sys/oss/gstossaudio.c @@ -0,0 +1,61 @@ +/* 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-i18n-plugin.h" + +#include "gstossmixerelement.h" +#include "gstosssink.h" +#include "gstosssrc.h" + +GST_DEBUG_CATEGORY (oss_debug); +#define GST_CAT_DEFAULT oss_debug + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "ossmixer", GST_RANK_NONE, + GST_TYPE_OSS_MIXER_ELEMENT) || + !gst_element_register (plugin, "osssrc", GST_RANK_SECONDARY, + GST_TYPE_OSS_SRC) || + !gst_element_register (plugin, "osssink", GST_RANK_SECONDARY, + GST_TYPE_OSSSINK)) { + return FALSE; + } + + GST_DEBUG_CATEGORY_INIT (oss_debug, "oss", 0, "OSS 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 /* ENABLE_NLS */ + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "ossaudio", + "OSS (Open Sound System) support for GStreamer", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/oss/gstossdmabuffer.h b/sys/oss/gstossdmabuffer.h new file mode 100644 index 0000000..c38ef6f --- /dev/null +++ b/sys/oss/gstossdmabuffer.h @@ -0,0 +1,77 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> + * 2005 Wim Taymans <wim@fluendo.com> + * + * gstossdmabuffer.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_OSSDMABUFFER_H__ +#define __GST_OSSDMABUFFER_H__ + +#include <gst/gst.h> + +#include "gstosshelper.h" +#include <gst/audio/gstringbuffer.h> + +G_BEGIN_DECLS + +#define GST_TYPE_OSSDMABUFFER (gst_ossdmabuffer_get_type()) +#define GST_OSSDMABUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSSDMABUFFER,GstOssDMABuffer)) +#define GST_OSSDMABUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSSDMABUFFER,GstOssDMABufferClass)) +#define GST_IS_OSSDMABUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSSDMABUFFER)) +#define GST_IS_OSSDMABUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSSDMABUFFER)) + +#define GST_OSSELEMENT_GET(obj) GST_OSSELEMENT (obj->element) + +typedef enum { + GST_OSSDMABUFFER_OPEN = (1 << 0), +} GstOssDMABufferFlags; + +typedef struct _GstOssDMABuffer GstOssDMABuffer; +typedef struct _GstOssDMABufferClass GstOssDMABufferClass; + +#define GST_OSSDMABUFFER_THREAD(buf) (GST_OSSDMABUFFER(buf)->thread) +#define GST_OSSDMABUFFER_LOCK GST_OBJECT_LOCK +#define GST_OSSDMABUFFER_UNLOCK GST_OBJECT_UNLOCK +#define GST_OSSDMABUFFER_COND(buf) (GST_OSSDMABUFFER(buf)->cond) +#define GST_OSSDMABUFFER_SIGNAL(buf) (g_cond_signal (GST_OSSDMABUFFER_COND (buf))) +#define GST_OSSDMABUFFER_WAIT(buf) (g_cond_wait (GST_OSSDMABUFFER_COND (buf), GST_OBJECT_GET_LOCK (buf))) + +struct _GstOssDMABuffer { + GstRingBuffer buffer; + + GstOssElement *element; + + int fd; + int caps; + int frag; + + GThread *thread; + GCond *cond; + gboolean running; +}; + +struct _GstOssDMABufferClass { + GstRingBufferClass parent_class; +}; + +GType gst_ossdmabuffer_get_type(void); + +G_END_DECLS + +#endif /* __GST_OSSDMABUFFER_H__ */ diff --git a/sys/oss/gstosshelper.c b/sys/oss/gstosshelper.c new file mode 100644 index 0000000..6d7e6bd --- /dev/null +++ b/sys/oss/gstosshelper.c @@ -0,0 +1,407 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> + * 2000 Wim Taymans <wim.taymans@chello.be> + * + * gstosshelper.c: OSS helper routines + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +#ifdef HAVE_OSS_INCLUDE_IN_SYS +# include <sys/soundcard.h> +#else +# ifdef HAVE_OSS_INCLUDE_IN_ROOT +# include <soundcard.h> +# else +# ifdef HAVE_OSS_INCLUDE_IN_MACHINE +# include <machine/soundcard.h> +# else +# error "What to include?" +# endif /* HAVE_OSS_INCLUDE_IN_MACHINE */ +# endif /* HAVE_OSS_INCLUDE_IN_ROOT */ +#endif /* HAVE_OSS_INCLUDE_IN_SYS */ + +#include <gst/interfaces/propertyprobe.h> + +#include "gstosshelper.h" +#include "gstossmixer.h" + +GST_DEBUG_CATEGORY_EXTERN (oss_debug); +#define GST_CAT_DEFAULT oss_debug + +typedef struct _GstOssProbe GstOssProbe; +struct _GstOssProbe +{ + int fd; + int format; + int n_channels; + GArray *rates; + int min; + int max; +}; + +typedef struct _GstOssRange GstOssRange; +struct _GstOssRange +{ + int min; + int max; +}; + +static GstStructure *gst_oss_helper_get_format_structure (unsigned int + format_bit); +static gboolean gst_oss_helper_rate_probe_check (GstOssProbe * probe); +static int gst_oss_helper_rate_check_rate (GstOssProbe * probe, int irate); +static void gst_oss_helper_rate_add_range (GQueue * queue, int min, int max); +static void gst_oss_helper_rate_add_rate (GArray * array, int rate); +static int gst_oss_helper_rate_int_compare (gconstpointer a, gconstpointer b); + +GstCaps * +gst_oss_helper_probe_caps (gint fd) +{ + GstOssProbe *probe; + int i; + gboolean ret; + GstStructure *structure; + unsigned int format_bit; + unsigned int format_mask; + GstCaps *caps; + + /* FIXME test make sure we're not currently playing */ + /* FIXME test both mono and stereo */ + + format_mask = AFMT_U8 | AFMT_S8; + + if (G_BYTE_ORDER == G_LITTLE_ENDIAN) + format_mask |= AFMT_S16_LE | AFMT_U16_LE; + else + format_mask |= AFMT_S16_BE | AFMT_U16_BE; + + caps = gst_caps_new_empty (); + + /* assume that the most significant bit of format_mask is 0 */ + for (format_bit = 1 << 31; format_bit > 0; format_bit >>= 1) { + if (format_bit & format_mask) { + GValue rate_value = { 0 }; + + probe = g_new0 (GstOssProbe, 1); + probe->fd = fd; + probe->format = format_bit; + /* FIXME: this is not working for all cards, see bug #518474 */ + probe->n_channels = 2; + + ret = gst_oss_helper_rate_probe_check (probe); + if (probe->min == -1 || probe->max == -1) { + g_array_free (probe->rates, TRUE); + g_free (probe); + continue; + } + + if (ret) { + GValue value = { 0 }; + + g_array_sort (probe->rates, gst_oss_helper_rate_int_compare); + + g_value_init (&rate_value, GST_TYPE_LIST); + g_value_init (&value, G_TYPE_INT); + + for (i = 0; i < probe->rates->len; i++) { + g_value_set_int (&value, g_array_index (probe->rates, int, i)); + + gst_value_list_append_value (&rate_value, &value); + } + + g_value_unset (&value); + } else { + /* one big range */ + g_value_init (&rate_value, GST_TYPE_INT_RANGE); + gst_value_set_int_range (&rate_value, probe->min, probe->max); + } + + g_array_free (probe->rates, TRUE); + g_free (probe); + + structure = gst_oss_helper_get_format_structure (format_bit); + gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); + gst_structure_set_value (structure, "rate", &rate_value); + g_value_unset (&rate_value); + + gst_caps_append_structure (caps, structure); + } + } + + if (gst_caps_is_empty (caps)) { + /* fixme: make user-visible */ + GST_WARNING ("Your OSS device could not be probed correctly"); + } + + GST_DEBUG ("probed caps: %" GST_PTR_FORMAT, caps); + + return caps; +} + +static GstStructure * +gst_oss_helper_get_format_structure (unsigned int format_bit) +{ + GstStructure *structure; + int endianness; + gboolean sign; + int width; + + switch (format_bit) { + case AFMT_U8: + endianness = 0; + sign = FALSE; + width = 8; + break; + case AFMT_S16_LE: + endianness = G_LITTLE_ENDIAN; + sign = TRUE; + width = 16; + break; + case AFMT_S16_BE: + endianness = G_BIG_ENDIAN; + sign = TRUE; + width = 16; + break; + case AFMT_S8: + endianness = 0; + sign = TRUE; + width = 8; + break; + case AFMT_U16_LE: + endianness = G_LITTLE_ENDIAN; + sign = FALSE; + width = 16; + break; + case AFMT_U16_BE: + endianness = G_BIG_ENDIAN; + sign = FALSE; + width = 16; + break; + default: + g_assert_not_reached (); + return NULL; + } + + structure = gst_structure_new ("audio/x-raw-int", + "width", G_TYPE_INT, width, + "depth", G_TYPE_INT, width, "signed", G_TYPE_BOOLEAN, sign, NULL); + + if (endianness) { + gst_structure_set (structure, "endianness", G_TYPE_INT, endianness, NULL); + } + + return structure; +} + +static gboolean +gst_oss_helper_rate_probe_check (GstOssProbe * probe) +{ + GstOssRange *range; + GQueue *ranges; + int exact_rates = 0; + gboolean checking_exact_rates = TRUE; + int n_checks = 0; + gboolean result = TRUE; + + ranges = g_queue_new (); + + probe->rates = g_array_new (FALSE, FALSE, sizeof (int)); + + probe->min = gst_oss_helper_rate_check_rate (probe, 1000); + n_checks++; + probe->max = gst_oss_helper_rate_check_rate (probe, 100000); + /* a little bug workaround */ + { + int max; + + max = gst_oss_helper_rate_check_rate (probe, 48000); + if (max > probe->max) { + GST_ERROR + ("Driver bug recognized (driver does not round rates correctly). Please file a bug report."); + probe->max = max; + } + } + n_checks++; + if (probe->min == -1 || probe->max == -1) { + /* This is a workaround for drivers that return -EINVAL (or another + * error) for rates outside of [8000,48000]. If this fails, the + * driver is seriously buggy, and probably doesn't work with other + * media libraries/apps. */ + probe->min = gst_oss_helper_rate_check_rate (probe, 8000); + probe->max = gst_oss_helper_rate_check_rate (probe, 48000); + } + if (probe->min == -1 || probe->max == -1) { + GST_DEBUG ("unexpected check_rate error"); + return FALSE; + } + gst_oss_helper_rate_add_range (ranges, probe->min + 1, probe->max - 1); + + while ((range = g_queue_pop_head (ranges))) { + int min1; + int max1; + int mid; + int mid_ret; + + GST_DEBUG ("checking [%d,%d]", range->min, range->max); + + mid = (range->min + range->max) / 2; + mid_ret = gst_oss_helper_rate_check_rate (probe, mid); + if (mid_ret == -1) { + /* FIXME ioctl returned an error. do something */ + GST_DEBUG ("unexpected check_rate error"); + } + n_checks++; + + if (mid == mid_ret && checking_exact_rates) { + int max_exact_matches = 20; + + exact_rates++; + if (exact_rates > max_exact_matches) { + GST_DEBUG ("got %d exact rates, assuming all are exact", + max_exact_matches); + result = FALSE; + g_free (range); + break; + } + } else { + checking_exact_rates = FALSE; + } + + /* Assume that the rate is arithmetically rounded to the nearest + * supported rate. */ + if (mid == mid_ret) { + min1 = mid - 1; + max1 = mid + 1; + } else { + if (mid < mid_ret) { + min1 = mid - (mid_ret - mid); + max1 = mid_ret + 1; + } else { + min1 = mid_ret - 1; + max1 = mid + (mid - mid_ret); + } + } + + gst_oss_helper_rate_add_range (ranges, range->min, min1); + gst_oss_helper_rate_add_range (ranges, max1, range->max); + + g_free (range); + } + + while ((range = g_queue_pop_head (ranges))) { + g_free (range); + } + g_queue_free (ranges); + + return result; +} + +static void +gst_oss_helper_rate_add_range (GQueue * queue, int min, int max) +{ + if (min <= max) { + GstOssRange *range = g_new0 (GstOssRange, 1); + + range->min = min; + range->max = max; + + g_queue_push_tail (queue, range); + /* push_head also works, but has different probing behavior */ + /*g_queue_push_head (queue, range); */ + } +} + +static int +gst_oss_helper_rate_check_rate (GstOssProbe * probe, int irate) +{ + int rate; + int format; + int n_channels; + int ret; + + rate = irate; + format = probe->format; + n_channels = probe->n_channels; + + GST_LOG ("checking format %d, channels %d, rate %d", + format, n_channels, rate); + ret = ioctl (probe->fd, SNDCTL_DSP_SETFMT, &format); + if (ret < 0 || format != probe->format) { + GST_DEBUG ("unsupported format: %d (%d)", probe->format, format); + return -1; + } + ret = ioctl (probe->fd, SNDCTL_DSP_CHANNELS, &n_channels); + if (ret < 0 || n_channels != probe->n_channels) { + GST_DEBUG ("unsupported channels: %d (%d)", probe->n_channels, n_channels); + return -1; + } + ret = ioctl (probe->fd, SNDCTL_DSP_SPEED, &rate); + if (ret < 0) { + GST_DEBUG ("unsupported rate: %d (%d)", irate, rate); + return -1; + } + + GST_DEBUG ("rate %d -> %d", irate, rate); + + if (rate == irate - 1 || rate == irate + 1) { + rate = irate; + } + gst_oss_helper_rate_add_rate (probe->rates, rate); + return rate; +} + +static void +gst_oss_helper_rate_add_rate (GArray * array, int rate) +{ + int i; + int val; + + for (i = 0; i < array->len; i++) { + val = g_array_index (array, int, i); + + if (val == rate) + return; + } + GST_DEBUG ("supported rate: %d", rate); + g_array_append_val (array, rate); +} + +static int +gst_oss_helper_rate_int_compare (gconstpointer a, gconstpointer b) +{ + const int *va = (const int *) a; + const int *vb = (const int *) b; + + if (*va < *vb) + return -1; + if (*va > *vb) + return 1; + return 0; +} diff --git a/sys/oss/gstosshelper.h b/sys/oss/gstosshelper.h new file mode 100644 index 0000000..1593fe3 --- /dev/null +++ b/sys/oss/gstosshelper.h @@ -0,0 +1,43 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> + * 2000 Wim Taymans <wim.taymans@chello.be> + * + * gstosshelper.h: OSS helper routines. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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_OSS_HELPER_H__ +#define __GST_OSS_HELPER_H__ + + +#include <gst/gst.h> +#include <sys/types.h> + +#include "gstosshelper.h" + + +G_BEGIN_DECLS + + +GstCaps* gst_oss_helper_probe_caps (gint fd); + + +G_END_DECLS + + +#endif /* __GST_OSS_HELPER_H__ */ diff --git a/sys/oss/gstossmixer.c b/sys/oss/gstossmixer.c new file mode 100644 index 0000000..e563031 --- /dev/null +++ b/sys/oss/gstossmixer.c @@ -0,0 +1,378 @@ +/* GStreamer OSS Mixer implementation + * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * + * gstossmixer.c: mixer interface implementation for OSS + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> + +#ifdef HAVE_OSS_INCLUDE_IN_SYS +# include <sys/soundcard.h> +#else +# ifdef HAVE_OSS_INCLUDE_IN_ROOT +# include <soundcard.h> +# else +# ifdef HAVE_OSS_INCLUDE_IN_MACHINE +# include <machine/soundcard.h> +# else +# error "What to include?" +# endif /* HAVE_OSS_INCLUDE_IN_MACHINE */ +# endif /* HAVE_OSS_INCLUDE_IN_ROOT */ +#endif /* HAVE_OSS_INCLUDE_IN_SYS */ + +#include <gst/gst-i18n-plugin.h> + +#include "gstossmixer.h" +#include "gstossmixertrack.h" + +GST_DEBUG_CATEGORY_EXTERN (oss_debug); +#define GST_CAT_DEFAULT oss_debug + +#define MASK_BIT_IS_SET(mask, bit) \ + (mask & (1 << bit)) + +static gboolean +gst_ossmixer_open (GstOssMixer * mixer) +{ +#ifdef SOUND_MIXER_INFO + struct mixer_info minfo; +#endif + + g_return_val_if_fail (mixer->mixer_fd == -1, FALSE); + + mixer->mixer_fd = open (mixer->device, O_RDWR); + if (mixer->mixer_fd == -1) + goto open_failed; + + /* get masks */ + if (ioctl (mixer->mixer_fd, SOUND_MIXER_READ_RECMASK, &mixer->recmask) < 0 + || ioctl (mixer->mixer_fd, SOUND_MIXER_READ_RECSRC, &mixer->recdevs) < 0 + || ioctl (mixer->mixer_fd, SOUND_MIXER_READ_STEREODEVS, + &mixer->stereomask) < 0 + || ioctl (mixer->mixer_fd, SOUND_MIXER_READ_DEVMASK, &mixer->devmask) < 0 + || ioctl (mixer->mixer_fd, SOUND_MIXER_READ_CAPS, &mixer->mixcaps) < 0) + goto masks_failed; + + /* get name, not fatal */ + g_free (mixer->cardname); +#ifdef SOUND_MIXER_INFO + if (ioctl (mixer->mixer_fd, SOUND_MIXER_INFO, &minfo) == 0) { + mixer->cardname = g_strdup (minfo.name); + GST_INFO ("Card name = %s", GST_STR_NULL (mixer->cardname)); + } else +#endif + { + mixer->cardname = g_strdup ("Unknown"); + GST_INFO ("Unknown card name"); + } + GST_INFO ("Opened mixer for device %s", mixer->device); + + return TRUE; + + /* ERRORS */ +open_failed: + { + /* this is valid. OSS devices don't need to expose a mixer */ + GST_DEBUG ("Failed to open mixer device %s, mixing disabled: %s", + mixer->device, strerror (errno)); + return FALSE; + } +masks_failed: + { + GST_DEBUG ("Failed to get device masks"); + close (mixer->mixer_fd); + mixer->mixer_fd = -1; + return FALSE; + } +} + +static void +gst_ossmixer_ensure_track_list (GstOssMixer * mixer) +{ + gint i, master = -1; + + g_return_if_fail (mixer->mixer_fd != -1); + + if (mixer->tracklist) + return; + + /* find master volume */ + if (mixer->devmask & SOUND_MASK_VOLUME) + master = SOUND_MIXER_VOLUME; + else if (mixer->devmask & SOUND_MASK_PCM) + master = SOUND_MIXER_PCM; + else if (mixer->devmask & SOUND_MASK_SPEAKER) + master = SOUND_MIXER_SPEAKER; /* doubtful... */ + /* else: no master, so we won't set any */ + + /* build track list */ + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (mixer->devmask & (1 << i)) { + GstMixerTrack *track; + gboolean input = FALSE, stereo = FALSE, record = FALSE; + + /* track exists, make up capabilities */ + if (MASK_BIT_IS_SET (mixer->stereomask, i)) + stereo = TRUE; + if (MASK_BIT_IS_SET (mixer->recmask, i)) + input = TRUE; + if (MASK_BIT_IS_SET (mixer->recdevs, i)) + record = TRUE; + + /* do we want this in our list? */ + if (!((mixer->dir & GST_OSS_MIXER_CAPTURE && input == TRUE) || + (mixer->dir & GST_OSS_MIXER_PLAYBACK && i != SOUND_MIXER_PCM))) + /* the PLAYBACK case seems hacky, but that's how 0.8 had it */ + continue; + + /* add track to list */ + track = gst_ossmixer_track_new (mixer->mixer_fd, i, stereo ? 2 : 1, + (record ? GST_MIXER_TRACK_RECORD : 0) | + (input ? GST_MIXER_TRACK_INPUT : + GST_MIXER_TRACK_OUTPUT) | + ((master != i) ? 0 : GST_MIXER_TRACK_MASTER)); + mixer->tracklist = g_list_append (mixer->tracklist, track); + } + } +} + +GstOssMixer * +gst_ossmixer_new (const char *device, GstOssMixerDirection dir) +{ + GstOssMixer *ret = NULL; + + g_return_val_if_fail (device != NULL, NULL); + + ret = g_new0 (GstOssMixer, 1); + + ret->device = g_strdup (device); + ret->dir = dir; + ret->mixer_fd = -1; + + if (!gst_ossmixer_open (ret)) + goto error; + + return ret; + + /* ERRORS */ +error: + { + gst_ossmixer_free (ret); + return NULL; + } +} + +void +gst_ossmixer_free (GstOssMixer * mixer) +{ + g_return_if_fail (mixer != NULL); + + if (mixer->device) { + g_free (mixer->device); + mixer->device = NULL; + } + + if (mixer->cardname) { + g_free (mixer->cardname); + mixer->cardname = NULL; + } + + if (mixer->tracklist) { + g_list_foreach (mixer->tracklist, (GFunc) g_object_unref, NULL); + g_list_free (mixer->tracklist); + mixer->tracklist = NULL; + } + + if (mixer->mixer_fd != -1) { + close (mixer->mixer_fd); + mixer->mixer_fd = -1; + } + + g_free (mixer); +} + +/* unused with G_DISABLE_* */ +static G_GNUC_UNUSED gboolean +gst_ossmixer_contains_track (GstOssMixer * mixer, GstOssMixerTrack * osstrack) +{ + const GList *item; + + for (item = mixer->tracklist; item != NULL; item = item->next) + if (item->data == osstrack) + return TRUE; + + return FALSE; +} + +const GList * +gst_ossmixer_list_tracks (GstOssMixer * mixer) +{ + gst_ossmixer_ensure_track_list (mixer); + + return (const GList *) mixer->tracklist; +} + +void +gst_ossmixer_get_volume (GstOssMixer * mixer, + GstMixerTrack * track, gint * volumes) +{ + gint volume; + GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track); + + g_return_if_fail (mixer->mixer_fd != -1); + g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack)); + + if (track->flags & GST_MIXER_TRACK_MUTE) { + volumes[0] = osstrack->lvol; + if (track->num_channels == 2) { + volumes[1] = osstrack->rvol; + } + } else { + /* get */ + if (ioctl (mixer->mixer_fd, MIXER_READ (osstrack->track_num), &volume) < 0) { + g_warning ("Error getting recording device (%d) volume: %s", + osstrack->track_num, strerror (errno)); + volume = 0; + } + + osstrack->lvol = volumes[0] = (volume & 0xff); + if (track->num_channels == 2) { + osstrack->rvol = volumes[1] = ((volume >> 8) & 0xff); + } + } +} + +void +gst_ossmixer_set_volume (GstOssMixer * mixer, + GstMixerTrack * track, gint * volumes) +{ + gint volume; + GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track); + + g_return_if_fail (mixer->mixer_fd != -1); + g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack)); + + /* prepare the value for ioctl() */ + if (!(track->flags & GST_MIXER_TRACK_MUTE)) { + volume = (volumes[0] & 0xff); + if (track->num_channels == 2) { + volume |= ((volumes[1] & 0xff) << 8); + } + + /* set */ + if (ioctl (mixer->mixer_fd, MIXER_WRITE (osstrack->track_num), &volume) < 0) { + g_warning ("Error setting recording device (%d) volume (0x%x): %s", + osstrack->track_num, volume, strerror (errno)); + return; + } + } + + osstrack->lvol = volumes[0]; + if (track->num_channels == 2) { + osstrack->rvol = volumes[1]; + } +} + +void +gst_ossmixer_set_mute (GstOssMixer * mixer, GstMixerTrack * track, + gboolean mute) +{ + int volume; + GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track); + + g_return_if_fail (mixer->mixer_fd != -1); + g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack)); + + if (mute) { + volume = 0; + } else { + volume = (osstrack->lvol & 0xff); + if (MASK_BIT_IS_SET (mixer->stereomask, osstrack->track_num)) { + volume |= ((osstrack->rvol & 0xff) << 8); + } + } + + if (ioctl (mixer->mixer_fd, MIXER_WRITE (osstrack->track_num), &volume) < 0) { + g_warning ("Error setting mixer recording device volume (0x%x): %s", + volume, strerror (errno)); + return; + } + + if (mute) { + track->flags |= GST_MIXER_TRACK_MUTE; + } else { + track->flags &= ~GST_MIXER_TRACK_MUTE; + } +} + +void +gst_ossmixer_set_record (GstOssMixer * mixer, + GstMixerTrack * track, gboolean record) +{ + GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track); + + g_return_if_fail (mixer->mixer_fd != -1); + g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack)); + + /* if there's nothing to do... */ + if ((record && GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD)) || + (!record && !GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD))) + return; + + /* if we're exclusive, then we need to unset the current one(s) */ + if (mixer->mixcaps & SOUND_CAP_EXCL_INPUT) { + GList *track; + + for (track = mixer->tracklist; track != NULL; track = track->next) { + GstMixerTrack *turn = (GstMixerTrack *) track->data; + + turn->flags &= ~GST_MIXER_TRACK_RECORD; + } + mixer->recdevs = 0; + } + + /* set new record bit, if needed */ + if (record) { + mixer->recdevs |= (1 << osstrack->track_num); + } else { + mixer->recdevs &= ~(1 << osstrack->track_num); + } + + /* set it to the device */ + if (ioctl (mixer->mixer_fd, SOUND_MIXER_WRITE_RECSRC, &mixer->recdevs) < 0) { + g_warning ("Error setting mixer recording devices (0x%x): %s", + mixer->recdevs, strerror (errno)); + return; + } + + if (record) { + track->flags |= GST_MIXER_TRACK_RECORD; + } else { + track->flags &= ~GST_MIXER_TRACK_RECORD; + } +} diff --git a/sys/oss/gstossmixer.h b/sys/oss/gstossmixer.h new file mode 100644 index 0000000..d2e06fe --- /dev/null +++ b/sys/oss/gstossmixer.h @@ -0,0 +1,171 @@ +/* GStreamer OSS Mixer implementation + * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * + * gstossmixer.h: mixer interface implementation for OSS + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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_OSS_MIXER_H__ +#define __GST_OSS_MIXER_H__ + + +#include <gst/gst.h> +#include <gst/interfaces/mixer.h> + +#include "gstosshelper.h" + + +G_BEGIN_DECLS + + +#define GST_OSS_MIXER(obj) ((GstOssMixer*)(obj)) + + +typedef enum { + GST_OSS_MIXER_CAPTURE = 1<<0, + GST_OSS_MIXER_PLAYBACK = 1<<1, + GST_OSS_MIXER_ALL = GST_OSS_MIXER_CAPTURE | GST_OSS_MIXER_PLAYBACK +} GstOssMixerDirection; + + +typedef struct _GstOssMixer GstOssMixer; + + +struct _GstOssMixer { + GList * tracklist; /* list of available tracks */ + + gint mixer_fd; + + gchar * device; + gchar * cardname; + + gint recmask; + gint recdevs; + gint stereomask; + gint devmask; + gint mixcaps; + + GstOssMixerDirection dir; +}; + + +GstOssMixer* gst_ossmixer_new (const gchar *device, + GstOssMixerDirection dir); +void gst_ossmixer_free (GstOssMixer *mixer); + +const GList* gst_ossmixer_list_tracks (GstOssMixer * mixer); +void gst_ossmixer_set_volume (GstOssMixer * mixer, + GstMixerTrack * track, + gint * volumes); +void gst_ossmixer_get_volume (GstOssMixer * mixer, + GstMixerTrack * track, + gint * volumes); +void gst_ossmixer_set_record (GstOssMixer * mixer, + GstMixerTrack * track, + gboolean record); +void gst_ossmixer_set_mute (GstOssMixer * mixer, + GstMixerTrack * track, + gboolean mute); + + +#define GST_IMPLEMENT_OSS_MIXER_METHODS(Type, interface_as_function) \ +static gboolean \ +interface_as_function ## _supported (Type *this, GType iface_type) \ +{ \ + g_assert (iface_type == GST_TYPE_MIXER); \ + \ + return (this->mixer != NULL); \ +} \ + \ +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_ossmixer_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_ossmixer_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_ossmixer_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_ossmixer_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_ossmixer_set_mute (this->mixer, track, mute); \ +} \ + \ +static void \ +interface_as_function ## _interface_init (GstMixerClass * klass) \ +{ \ + GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; \ + \ + /* set up the interface hooks */ \ + 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; \ +} + + +G_END_DECLS + + +#endif /* __GST_OSS_MIXER_H__ */ diff --git a/sys/oss/gstossmixerelement.c b/sys/oss/gstossmixerelement.c new file mode 100644 index 0000000..7ceb2b8 --- /dev/null +++ b/sys/oss/gstossmixerelement.c @@ -0,0 +1,218 @@ +/* OSS mixer interface element. + * Copyright (C) 2005 Andrew Vander Wingo <wingo@pobox.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-ossmixer + * + * This element lets you adjust sound input and output levels with the + * Open Sound System (OSS). 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> + * ossmixer can't be used in a sensible way in gst-launch. + * </para> + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstossmixerelement.h" + +GST_DEBUG_CATEGORY_EXTERN (oss_debug); +#define GST_CAT_DEFAULT oss_debug + +#define DEFAULT_DEVICE "/dev/mixer" +#define DEFAULT_DEVICE_NAME NULL + +enum +{ + PROP_0, + PROP_DEVICE, + PROP_DEVICE_NAME +}; + +GST_BOILERPLATE_WITH_INTERFACE (GstOssMixerElement, gst_oss_mixer_element, + GstElement, GST_TYPE_ELEMENT, GstMixer, GST_TYPE_MIXER, + gst_oss_mixer_element); + +GST_IMPLEMENT_OSS_MIXER_METHODS (GstOssMixerElement, gst_oss_mixer_element); + +static GstStateChangeReturn gst_oss_mixer_element_change_state (GstElement * + element, GstStateChange transition); + +static void gst_oss_mixer_element_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_oss_mixer_element_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); +static void gst_oss_mixer_element_finalize (GObject * object); + +static void +gst_oss_mixer_element_base_init (gpointer klass) +{ + gst_element_class_set_details_simple (GST_ELEMENT_CLASS (klass), "OSS Mixer", + "Generic/Audio", + "Control sound input and output levels with OSS", + "Andrew Vander Wingo <wingo@pobox.com>"); +} + +static void +gst_oss_mixer_element_class_init (GstOssMixerElementClass * klass) +{ + GstElementClass *element_class; + GObjectClass *gobject_class; + + element_class = (GstElementClass *) klass; + gobject_class = (GObjectClass *) klass; + + gobject_class->finalize = gst_oss_mixer_element_finalize; + gobject_class->set_property = gst_oss_mixer_element_set_property; + gobject_class->get_property = gst_oss_mixer_element_get_property; + + /** + * GstOssMixerElement:device + * + * OSS mixer device (usually /dev/mixer) + * + * Since: 0.10.5 + **/ + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", + "OSS mixer device (usually /dev/mixer)", 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)); + + element_class->change_state = + GST_DEBUG_FUNCPTR (gst_oss_mixer_element_change_state); +} + +static void +gst_oss_mixer_element_finalize (GObject * obj) +{ + GstOssMixerElement *this = GST_OSS_MIXER_ELEMENT (obj); + + g_free (this->device); + + G_OBJECT_CLASS (parent_class)->finalize (obj); +} + +static void +gst_oss_mixer_element_init (GstOssMixerElement * this, + GstOssMixerElementClass * g_class) +{ + this->mixer = NULL; + this->device = g_strdup (DEFAULT_DEVICE); +} + +static void +gst_oss_mixer_element_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOssMixerElement *this = GST_OSS_MIXER_ELEMENT (object); + + switch (prop_id) { + case PROP_DEVICE: + g_free (this->device); + this->device = g_value_dup_string (value); + /* make sure we never set NULL */ + if (this->device == NULL) { + this->device = g_strdup (DEFAULT_DEVICE); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_oss_mixer_element_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstOssMixerElement *this = GST_OSS_MIXER_ELEMENT (object); + + switch (prop_id) { + case PROP_DEVICE: + g_value_set_string (value, this->device); + break; + case PROP_DEVICE_NAME: + if (this->mixer) { + g_value_set_string (value, this->mixer->cardname); + } else { + g_value_set_string (value, NULL); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstStateChangeReturn +gst_oss_mixer_element_change_state (GstElement * element, + GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstOssMixerElement *this = GST_OSS_MIXER_ELEMENT (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!this->mixer) { + this->mixer = gst_ossmixer_new (this->device, GST_OSS_MIXER_ALL); + if (!this->mixer) + goto open_failed; + } + break; + 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_READY_TO_NULL: + if (this->mixer) { + gst_ossmixer_free (this->mixer); + this->mixer = NULL; + } + break; + default: + break; + } + return ret; + + /* ERRORS */ +open_failed: + { + GST_ELEMENT_ERROR (element, RESOURCE, OPEN_READ_WRITE, (NULL), + ("Failed to open oss mixer device '%s'", this->device)); + return GST_STATE_CHANGE_FAILURE; + } +} diff --git a/sys/oss/gstossmixerelement.h b/sys/oss/gstossmixerelement.h new file mode 100644 index 0000000..2d47e0e --- /dev/null +++ b/sys/oss/gstossmixerelement.h @@ -0,0 +1,59 @@ +/* OSS mixer interface element. + * Copyright (C) 2005 Andrew Vander Wingo <wingo@pobox.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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef __GST_OSS_MIXER_ELEMENT_H__ +#define __GST_OSS_MIXER_ELEMENT_H__ + + +#include "gstossmixer.h" + + +G_BEGIN_DECLS + + +#define GST_OSS_MIXER_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS_MIXER_ELEMENT,GstOssMixerElement)) +#define GST_OSS_MIXER_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS_MIXER_ELEMENT,GstOssMixerElementClass)) +#define GST_IS_OSS_MIXER_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS_MIXER_ELEMENT)) +#define GST_IS_OSS_MIXER_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS_MIXER_ELEMENT)) +#define GST_TYPE_OSS_MIXER_ELEMENT (gst_oss_mixer_element_get_type()) + + +typedef struct _GstOssMixerElement GstOssMixerElement; +typedef struct _GstOssMixerElementClass GstOssMixerElementClass; + + +struct _GstOssMixerElement { + GstElement parent; + + gchar *device; + GstOssMixer *mixer; +}; + +struct _GstOssMixerElementClass { + GstElementClass parent; +}; + + +GType gst_oss_mixer_element_get_type (void); + + +G_END_DECLS + + +#endif /* __GST_OSS_MIXER_ELEMENT_H__ */ diff --git a/sys/oss/gstossmixertrack.c b/sys/oss/gstossmixertrack.c new file mode 100644 index 0000000..3bc8cde --- /dev/null +++ b/sys/oss/gstossmixertrack.c @@ -0,0 +1,172 @@ +/* GStreamer OSS Mixer implementation + * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * + * gstossmixer.c: mixer interface implementation for OSS + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> + +#ifdef HAVE_OSS_INCLUDE_IN_SYS +# include <sys/soundcard.h> +#else +# ifdef HAVE_OSS_INCLUDE_IN_ROOT +# include <soundcard.h> +# else +# ifdef HAVE_OSS_INCLUDE_IN_MACHINE +# include <machine/soundcard.h> +# else +# error "What to include?" +# endif /* HAVE_OSS_INCLUDE_IN_MACHINE */ +# endif /* HAVE_OSS_INCLUDE_IN_ROOT */ +#endif /* HAVE_OSS_INCLUDE_IN_SYS */ + +#include <gst/gst-i18n-plugin.h> + +#include "gstossmixertrack.h" + +GST_DEBUG_CATEGORY_EXTERN (oss_debug); +#define GST_CAT_DEFAULT oss_debug + +#define MASK_BIT_IS_SET(mask, bit) \ + (mask & (1 << bit)) + +G_DEFINE_TYPE (GstOssMixerTrack, gst_ossmixer_track, GST_TYPE_MIXER_TRACK); + +static void +gst_ossmixer_track_class_init (GstOssMixerTrackClass * klass) +{ + /* nop */ +} + +static void +gst_ossmixer_track_init (GstOssMixerTrack * track) +{ + track->lvol = track->rvol = 0; + track->track_num = 0; +} + +static const gchar **labels = NULL; + +/* three functions: firstly, OSS has the nasty habit of inserting + * spaces in the labels, we want to get rid of them. Secondly, + * i18n is impossible with OSS' way of providing us with mixer + * labels, so we make a 'given' list of i18n'ed labels. Thirdly, I + * personally don't like the "1337" names that OSS gives to their + * labels ("Vol", "Mic", "Rec"), I'd rather see full names. */ + +static void +fill_labels (void) +{ + gint i, pos; + const gchar *origs[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; + const struct + { + const gchar *given; + const gchar *wanted; + } + cases[] = { + /* Note: this list is simply ripped from soundcard.h. For + * some people, some values might be missing (3D surround, + * etc.) - feel free to add them. That's the reason why + * I'm doing this in such a horribly complicated way. */ + { + "Vol ", _("Volume")}, { + "Bass ", _("Bass")}, { + "Trebl", _("Treble")}, { + "Synth", _("Synth")}, { + "Pcm ", _("PCM")}, { + "Spkr ", _("Speaker")}, { + "Line ", _("Line-in")}, { + "Mic ", _("Microphone")}, { + "CD ", _("CD")}, { + "Mix ", _("Mixer")}, { + "Pcm2 ", _("PCM-2")}, { + "Rec ", _("Record")}, { + "IGain", _("In-gain")}, { + "OGain", _("Out-gain")}, { + "Line1", _("Line-1")}, { + "Line2", _("Line-2")}, { + "Line3", _("Line-3")}, { + "Digital1", _("Digital-1")}, { + "Digital2", _("Digital-2")}, { + "Digital3", _("Digital-3")}, { + "PhoneIn", _("Phone-in")}, { + "PhoneOut", _("Phone-out")}, { + "Video", _("Video")}, { + "Radio", _("Radio")}, { + "Monitor", _("Monitor")}, { + NULL, NULL} + }; + + labels = g_malloc (sizeof (gchar *) * SOUND_MIXER_NRDEVICES); + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + for (pos = 0; cases[pos].given != NULL; pos++) { + if (!strcmp (cases[pos].given, origs[i])) { + labels[i] = g_strdup (cases[pos].wanted); + break; + } + } + if (cases[pos].given == NULL) + labels[i] = g_strdup (origs[i]); + } +} + +GstMixerTrack * +gst_ossmixer_track_new (gint mixer_fd, + gint track_num, gint max_chans, gint flags) +{ + GstOssMixerTrack *osstrack; + GstMixerTrack *track; + gint volume; + + if (!labels) + fill_labels (); + + osstrack = g_object_new (GST_TYPE_OSSMIXER_TRACK, NULL); + track = GST_MIXER_TRACK (osstrack); + track->label = g_strdup (labels[track_num]); + track->num_channels = max_chans; + track->flags = flags; + track->min_volume = 0; + track->max_volume = 100; + osstrack->track_num = track_num; + + /* volume */ + if (ioctl (mixer_fd, MIXER_READ (osstrack->track_num), &volume) < 0) { + g_warning ("Error getting device (%d) volume: %s", + osstrack->track_num, strerror (errno)); + volume = 0; + } + osstrack->lvol = (volume & 0xff); + if (track->num_channels == 2) { + osstrack->rvol = ((volume >> 8) & 0xff); + } + + return track; +} diff --git a/sys/oss/gstossmixertrack.h b/sys/oss/gstossmixertrack.h new file mode 100644 index 0000000..2e62ec8 --- /dev/null +++ b/sys/oss/gstossmixertrack.h @@ -0,0 +1,62 @@ +/* GStreamer OSS Mixer implementation + * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * + * gstossmixertrack.h: OSS mixer tracks + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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_OSS_MIXER_TRACK_H__ +#define __GST_OSS_MIXER_TRACK_H__ + +#include <gst/gst.h> +#include <gst/interfaces/mixer.h> + +#include "gstosshelper.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OSSMIXER_TRACK \ + (gst_ossmixer_track_get_type ()) +#define GST_OSSMIXER_TRACK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OSSMIXER_TRACK, \ + GstOssMixerTrack)) +#define GST_OSSMIXER_TRACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_OSSMIXER_TRACK, \ + GstOssMixerTrackClass)) +#define GST_IS_OSSMIXER_TRACK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OSSMIXER_TRACK)) +#define GST_IS_OSSMIXER_TRACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_OSSMIXER_TRACK)) + +typedef struct _GstOssMixerTrack { + GstMixerTrack parent; + + gint lvol, rvol; + gint track_num; +} GstOssMixerTrack; + +typedef struct _GstOssMixerTrackClass { + GstMixerTrackClass parent; +} GstOssMixerTrackClass; + +GType gst_ossmixer_track_get_type (void); +GstMixerTrack* gst_ossmixer_track_new (gint mixer_fd, + gint track_num, gint max_chans, gint flags); + +G_END_DECLS + +#endif /* __GST_OSS_MIXER_TRACK_H__ */ diff --git a/sys/oss/gstosssink.c b/sys/oss/gstosssink.c new file mode 100644 index 0000000..a604d9c --- /dev/null +++ b/sys/oss/gstosssink.c @@ -0,0 +1,565 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> + * 2000,2005 Wim Taymans <wim@fluendo.com> + * + * gstosssink.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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-osssink + * + * This element lets you output sound using the Open Sound System (OSS). + * + * Note that you should almost always use generic audio conversion elements + * like audioconvert and audioresample in front of an audiosink to make sure + * your pipeline works under all circumstances (those conversion elements will + * act in passthrough-mode if no conversion is necessary). + * + * <refsect2> + * <title>Example pipelines</title> + * |[ + * gst-launch -v audiotestsrc ! audioconvert ! volume volume=0.1 ! osssink + * ]| will output a sine wave (continuous beep sound) to your sound card (with + * a very low volume as precaution). + * |[ + * gst-launch -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! osssink + * ]| will play an Ogg/Vorbis audio file and output it using the Open Sound System. + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <sys/ioctl.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> + +#ifdef HAVE_OSS_INCLUDE_IN_SYS +# include <sys/soundcard.h> +#else +# ifdef HAVE_OSS_INCLUDE_IN_ROOT +# include <soundcard.h> +# else +# ifdef HAVE_OSS_INCLUDE_IN_MACHINE +# include <machine/soundcard.h> +# else +# error "What to include?" +# endif /* HAVE_OSS_INCLUDE_IN_MACHINE */ +# endif /* HAVE_OSS_INCLUDE_IN_ROOT */ +#endif /* HAVE_OSS_INCLUDE_IN_SYS */ + +#include "common.h" +#include "gstosssink.h" + +#include <gst/gst-i18n-plugin.h> + +GST_DEBUG_CATEGORY_EXTERN (oss_debug); +#define GST_CAT_DEFAULT oss_debug + +static void gst_oss_sink_base_init (gpointer g_class); +static void gst_oss_sink_class_init (GstOssSinkClass * klass); +static void gst_oss_sink_init (GstOssSink * osssink); + +static void gst_oss_sink_dispose (GObject * object); +static void gst_oss_sink_finalise (GObject * object); + +static void gst_oss_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_oss_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); + +static GstCaps *gst_oss_sink_getcaps (GstBaseSink * bsink); + +static gboolean gst_oss_sink_open (GstAudioSink * asink); +static gboolean gst_oss_sink_close (GstAudioSink * asink); +static gboolean gst_oss_sink_prepare (GstAudioSink * asink, + GstRingBufferSpec * spec); +static gboolean gst_oss_sink_unprepare (GstAudioSink * asink); +static guint gst_oss_sink_write (GstAudioSink * asink, gpointer data, + guint length); +static guint gst_oss_sink_delay (GstAudioSink * asink); +static void gst_oss_sink_reset (GstAudioSink * asink); + +/* OssSink signals and args */ +enum +{ + LAST_SIGNAL +}; + +#define DEFAULT_DEVICE "/dev/dsp" +enum +{ + PROP_0, + PROP_DEVICE, +}; + +static GstStaticPadTemplate osssink_sink_factory = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, " + "signed = (boolean) { TRUE, FALSE }, " + "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 GstElementClass *parent_class = NULL; + +/* static guint gst_oss_sink_signals[LAST_SIGNAL] = { 0 }; */ + +GType +gst_oss_sink_get_type (void) +{ + static GType osssink_type = 0; + + if (!osssink_type) { + static const GTypeInfo osssink_info = { + sizeof (GstOssSinkClass), + gst_oss_sink_base_init, + NULL, + (GClassInitFunc) gst_oss_sink_class_init, + NULL, + NULL, + sizeof (GstOssSink), + 0, + (GInstanceInitFunc) gst_oss_sink_init, + }; + + osssink_type = + g_type_register_static (GST_TYPE_AUDIO_SINK, "GstOssSink", + &osssink_info, 0); + } + + return osssink_type; +} + +static void +gst_oss_sink_dispose (GObject * object) +{ + GstOssSink *osssink = GST_OSSSINK (object); + + if (osssink->probed_caps) { + gst_caps_unref (osssink->probed_caps); + osssink->probed_caps = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_oss_sink_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details_simple (element_class, "Audio Sink (OSS)", + "Sink/Audio", + "Output to a sound card via OSS", + "Erik Walthinsen <omega@cse.ogi.edu>, " + "Wim Taymans <wim.taymans@chello.be>"); + + gst_element_class_add_static_pad_template (element_class, + &osssink_sink_factory); +} + +static void +gst_oss_sink_class_init (GstOssSinkClass * 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->dispose = gst_oss_sink_dispose; + gobject_class->finalize = gst_oss_sink_finalise; + gobject_class->get_property = gst_oss_sink_get_property; + gobject_class->set_property = gst_oss_sink_set_property; + + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", + "OSS device (usually /dev/dspN)", DEFAULT_DEVICE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_oss_sink_getcaps); + + gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_oss_sink_open); + gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_oss_sink_close); + gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_oss_sink_prepare); + gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_oss_sink_unprepare); + gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_oss_sink_write); + gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_oss_sink_delay); + gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_oss_sink_reset); +} + +static void +gst_oss_sink_init (GstOssSink * osssink) +{ + const gchar *device; + + GST_DEBUG_OBJECT (osssink, "initializing osssink"); + + device = g_getenv ("AUDIODEV"); + if (device == NULL) + device = DEFAULT_DEVICE; + osssink->device = g_strdup (device); + osssink->fd = -1; +} + +static void +gst_oss_sink_finalise (GObject * object) +{ + GstOssSink *osssink = GST_OSSSINK (object); + + g_free (osssink->device); + + G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (object)); +} + +static void +gst_oss_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOssSink *sink; + + sink = GST_OSSSINK (object); + + switch (prop_id) { + case PROP_DEVICE: + g_free (sink->device); + sink->device = g_value_dup_string (value); + if (sink->probed_caps) { + gst_caps_unref (sink->probed_caps); + sink->probed_caps = NULL; + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_oss_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstOssSink *sink; + + sink = GST_OSSSINK (object); + + switch (prop_id) { + case PROP_DEVICE: + g_value_set_string (value, sink->device); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstCaps * +gst_oss_sink_getcaps (GstBaseSink * bsink) +{ + GstOssSink *osssink; + GstCaps *caps; + + osssink = GST_OSSSINK (bsink); + + if (osssink->fd == -1) { + caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD + (bsink))); + } else if (osssink->probed_caps) { + caps = gst_caps_copy (osssink->probed_caps); + } else { + caps = gst_oss_helper_probe_caps (osssink->fd); + if (caps && !gst_caps_is_empty (caps)) { + osssink->probed_caps = gst_caps_copy (caps); + } + } + + return caps; +} + +static gint +ilog2 (gint x) +{ + /* well... hacker's delight explains... */ + x = x | (x >> 1); + x = x | (x >> 2); + x = x | (x >> 4); + x = x | (x >> 8); + x = x | (x >> 16); + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0f0f0f0f; + x = x + (x >> 8); + x = x + (x >> 16); + return (x & 0x0000003f) - 1; +} + +static gint +gst_oss_sink_get_format (GstBufferFormat fmt) +{ + gint result; + + switch (fmt) { + case GST_MU_LAW: + result = AFMT_MU_LAW; + break; + case GST_A_LAW: + result = AFMT_A_LAW; + break; + case GST_IMA_ADPCM: + result = AFMT_IMA_ADPCM; + break; + case GST_U8: + result = AFMT_U8; + break; + case GST_S16_LE: + result = AFMT_S16_LE; + break; + case GST_S16_BE: + result = AFMT_S16_BE; + break; + case GST_S8: + result = AFMT_S8; + break; + case GST_U16_LE: + result = AFMT_U16_LE; + break; + case GST_U16_BE: + result = AFMT_U16_BE; + break; + case GST_MPEG: + result = AFMT_MPEG; + break; + default: + result = 0; + break; + } + return result; +} + +static gboolean +gst_oss_sink_open (GstAudioSink * asink) +{ + GstOssSink *oss; + int mode; + + oss = GST_OSSSINK (asink); + + mode = O_WRONLY; + mode |= O_NONBLOCK; + + oss->fd = open (oss->device, mode, 0); + if (oss->fd == -1) { + switch (errno) { + case EBUSY: + goto busy; + case EACCES: + goto no_permission; + default: + goto open_failed; + } + } + + return TRUE; + + /* ERRORS */ +busy: + { + GST_ELEMENT_ERROR (oss, RESOURCE, BUSY, + (_("Could not open audio device for playback. " + "Device is being used by another application.")), (NULL)); + return FALSE; + } +no_permission: + { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE, + (_("Could not open audio device for playback. " + "You don't have permission to open the device.")), + GST_ERROR_SYSTEM); + return FALSE; + } +open_failed: + { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE, + (_("Could not open audio device for playback.")), GST_ERROR_SYSTEM); + return FALSE; + } +} + +static gboolean +gst_oss_sink_close (GstAudioSink * asink) +{ + close (GST_OSSSINK (asink)->fd); + GST_OSSSINK (asink)->fd = -1; + return TRUE; +} + +static gboolean +gst_oss_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) +{ + GstOssSink *oss; + struct audio_buf_info info; + int mode; + int tmp; + + oss = GST_OSSSINK (asink); + + /* we opened non-blocking so that we can detect if the device is available + * without hanging forever. We now want to remove the non-blocking flag. */ + mode = fcntl (oss->fd, F_GETFL); + mode &= ~O_NONBLOCK; + if (fcntl (oss->fd, F_SETFL, mode) == -1) { + /* some drivers do no support unsetting the non-blocking flag, try to + * close/open the device then. This is racy but we error out properly. */ + gst_oss_sink_close (asink); + if ((oss->fd = open (oss->device, O_WRONLY, 0)) == -1) + goto non_block; + } + + tmp = gst_oss_sink_get_format (spec->format); + if (tmp == 0) + goto wrong_format; + + if (spec->width != 16 && spec->width != 8) + goto dodgy_width; + + SET_PARAM (oss, SNDCTL_DSP_SETFMT, tmp, "SETFMT"); + if (spec->channels == 2) + SET_PARAM (oss, SNDCTL_DSP_STEREO, 1, "STEREO"); + SET_PARAM (oss, SNDCTL_DSP_CHANNELS, spec->channels, "CHANNELS"); + SET_PARAM (oss, SNDCTL_DSP_SPEED, spec->rate, "SPEED"); + + tmp = ilog2 (spec->segsize); + tmp = ((spec->segtotal & 0x7fff) << 16) | tmp; + GST_DEBUG_OBJECT (oss, "set segsize: %d, segtotal: %d, value: %08x", + spec->segsize, spec->segtotal, tmp); + + SET_PARAM (oss, SNDCTL_DSP_SETFRAGMENT, tmp, "SETFRAGMENT"); + GET_PARAM (oss, SNDCTL_DSP_GETOSPACE, &info, "GETOSPACE"); + + spec->segsize = info.fragsize; + spec->segtotal = info.fragstotal; + + spec->bytes_per_sample = (spec->width / 8) * spec->channels; + oss->bytes_per_sample = (spec->width / 8) * spec->channels; + + GST_DEBUG_OBJECT (oss, "got segsize: %d, segtotal: %d, value: %08x", + spec->segsize, spec->segtotal, tmp); + + return TRUE; + + /* ERRORS */ +non_block: + { + GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL), + ("Unable to set device %s in non blocking mode: %s", + oss->device, g_strerror (errno))); + return FALSE; + } +wrong_format: + { + GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL), + ("Unable to get format %d", spec->format)); + return FALSE; + } +dodgy_width: + { + GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL), + ("unexpected width %d", spec->width)); + return FALSE; + } +} + +static gboolean +gst_oss_sink_unprepare (GstAudioSink * asink) +{ + /* could do a SNDCTL_DSP_RESET, but the OSS manual recommends a close/open */ + + if (!gst_oss_sink_close (asink)) + goto couldnt_close; + + if (!gst_oss_sink_open (asink)) + goto couldnt_reopen; + + return TRUE; + + /* ERRORS */ +couldnt_close: + { + GST_DEBUG_OBJECT (asink, "Could not close the audio device"); + return FALSE; + } +couldnt_reopen: + { + GST_DEBUG_OBJECT (asink, "Could not reopen the audio device"); + return FALSE; + } +} + +static guint +gst_oss_sink_write (GstAudioSink * asink, gpointer data, guint length) +{ + return write (GST_OSSSINK (asink)->fd, data, length); +} + +static guint +gst_oss_sink_delay (GstAudioSink * asink) +{ + GstOssSink *oss; + gint delay = 0; + gint ret; + + oss = GST_OSSSINK (asink); + +#ifdef SNDCTL_DSP_GETODELAY + ret = ioctl (oss->fd, SNDCTL_DSP_GETODELAY, &delay); +#else + ret = -1; +#endif + if (ret < 0) { + audio_buf_info info; + + ret = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &info); + + delay = (ret < 0 ? 0 : (info.fragstotal * info.fragsize) - info.bytes); + } + return delay / oss->bytes_per_sample; +} + +static void +gst_oss_sink_reset (GstAudioSink * asink) +{ + /* There's nothing we can do here really: OSS can't handle access to the + * same device/fd from multiple threads and might deadlock or blow up in + * other ways if we try an ioctl SNDCTL_DSP_RESET or similar */ +} diff --git a/sys/oss/gstosssink.h b/sys/oss/gstosssink.h new file mode 100644 index 0000000..bb2ca93 --- /dev/null +++ b/sys/oss/gstosssink.h @@ -0,0 +1,62 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> + * 2000 Wim Taymans <wtay@chello.be> + * + * gstosssink.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_OSSSINK_H__ +#define __GST_OSSSINK_H__ + + +#include <gst/gst.h> +#include <gst/audio/gstaudiosink.h> + +#include "gstosshelper.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OSSSINK (gst_oss_sink_get_type()) +#define GST_OSSSINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSSSINK,GstOssSink)) +#define GST_OSSSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSSSINK,GstOssSinkClass)) +#define GST_IS_OSSSINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSSSINK)) +#define GST_IS_OSSSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSSSINK)) + +typedef struct _GstOssSink GstOssSink; +typedef struct _GstOssSinkClass GstOssSinkClass; + +struct _GstOssSink { + GstAudioSink sink; + + gchar *device; + gint fd; + gint bytes_per_sample; + + GstCaps *probed_caps; +}; + +struct _GstOssSinkClass { + GstAudioSinkClass parent_class; +}; + +GType gst_oss_sink_get_type(void); + +G_END_DECLS + +#endif /* __GST_OSSSINK_H__ */ diff --git a/sys/oss/gstosssrc.c b/sys/oss/gstosssrc.c new file mode 100644 index 0000000..2bd931b --- /dev/null +++ b/sys/oss/gstosssrc.c @@ -0,0 +1,537 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> + * 2000,2005 Wim Taymans <wim@fluendo.com> + * + * gstosssrc.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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-osssrc + * + * This element lets you record sound using the Open Sound System (OSS). + * + * <refsect2> + * <title>Example pipelines</title> + * |[ + * gst-launch -v osssrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=mymusic.ogg + * ]| will record sound from your sound card using OSS and encode it to an + * Ogg/Vorbis file (this will only work if your mixer settings are right + * and the right inputs enabled etc.) + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/ioctl.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> + +#ifdef HAVE_OSS_INCLUDE_IN_SYS +# include <sys/soundcard.h> +#else +# ifdef HAVE_OSS_INCLUDE_IN_ROOT +# include <soundcard.h> +# else +# ifdef HAVE_OSS_INCLUDE_IN_MACHINE +# include <machine/soundcard.h> +# else +# error "What to include?" +# endif /* HAVE_OSS_INCLUDE_IN_MACHINE */ +# endif /* HAVE_OSS_INCLUDE_IN_ROOT */ +#endif /* HAVE_OSS_INCLUDE_IN_SYS */ + +#include "gstosssrc.h" +#include "common.h" + +#include <gst/gst-i18n-plugin.h> + +GST_DEBUG_CATEGORY_EXTERN (oss_debug); +#define GST_CAT_DEFAULT oss_debug + +#define DEFAULT_DEVICE "/dev/dsp" +#define DEFAULT_DEVICE_NAME "" + +enum +{ + PROP_0, + PROP_DEVICE, + PROP_DEVICE_NAME, +}; + +GST_BOILERPLATE_WITH_INTERFACE (GstOssSrc, gst_oss_src, GstAudioSrc, + GST_TYPE_AUDIO_SRC, GstMixer, GST_TYPE_MIXER, gst_oss_src_mixer); + +GST_IMPLEMENT_OSS_MIXER_METHODS (GstOssSrc, gst_oss_src_mixer); + +static void gst_oss_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_oss_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); + +static void gst_oss_src_dispose (GObject * object); +static void gst_oss_src_finalize (GstOssSrc * osssrc); + +static GstCaps *gst_oss_src_getcaps (GstBaseSrc * bsrc); + +static gboolean gst_oss_src_open (GstAudioSrc * asrc); +static gboolean gst_oss_src_close (GstAudioSrc * asrc); +static gboolean gst_oss_src_prepare (GstAudioSrc * asrc, + GstRingBufferSpec * spec); +static gboolean gst_oss_src_unprepare (GstAudioSrc * asrc); +static guint gst_oss_src_read (GstAudioSrc * asrc, gpointer data, guint length); +static guint gst_oss_src_delay (GstAudioSrc * asrc); +static void gst_oss_src_reset (GstAudioSrc * asrc); + + + +static GstStaticPadTemplate osssrc_src_factory = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, " + "signed = (boolean) { TRUE, FALSE }, " + "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_oss_src_dispose (GObject * object) +{ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_oss_src_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details_simple (element_class, "Audio Source (OSS)", + "Source/Audio", + "Capture from a sound card via OSS", + "Erik Walthinsen <omega@cse.ogi.edu>, " "Wim Taymans <wim@fluendo.com>"); + + gst_element_class_add_static_pad_template (element_class, + &osssrc_src_factory); +} + +static void +gst_oss_src_class_init (GstOssSrcClass * klass) +{ + GObjectClass *gobject_class; + GstBaseSrcClass *gstbasesrc_class; + GstAudioSrcClass *gstaudiosrc_class; + + gobject_class = (GObjectClass *) klass; + gstbasesrc_class = (GstBaseSrcClass *) klass; + gstaudiosrc_class = (GstAudioSrcClass *) klass; + + gobject_class->dispose = gst_oss_src_dispose; + gobject_class->finalize = (GObjectFinalizeFunc) gst_oss_src_finalize; + gobject_class->get_property = gst_oss_src_get_property; + gobject_class->set_property = gst_oss_src_set_property; + + gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_oss_src_getcaps); + + gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_oss_src_open); + gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_oss_src_prepare); + gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_oss_src_unprepare); + gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_oss_src_close); + gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_oss_src_read); + gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_oss_src_delay); + gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_oss_src_reset); + + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", + "OSS device (usually /dev/dspN)", 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)); +} + +static void +gst_oss_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOssSrc *src; + + src = GST_OSS_SRC (object); + + switch (prop_id) { + case PROP_DEVICE: + if (src->device) + g_free (src->device); + src->device = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_oss_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstOssSrc *src; + + src = GST_OSS_SRC (object); + + switch (prop_id) { + case PROP_DEVICE: + g_value_set_string (value, src->device); + break; + case PROP_DEVICE_NAME: + g_value_set_string (value, src->device_name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_oss_src_init (GstOssSrc * osssrc, GstOssSrcClass * g_class) +{ + const gchar *device; + + GST_DEBUG ("initializing osssrc"); + + device = g_getenv ("AUDIODEV"); + if (device == NULL) + device = DEFAULT_DEVICE; + + osssrc->fd = -1; + osssrc->device = g_strdup (device); + osssrc->device_name = g_strdup (DEFAULT_DEVICE_NAME); + osssrc->probed_caps = NULL; +} + +static void +gst_oss_src_finalize (GstOssSrc * osssrc) +{ + g_free (osssrc->device); + g_free (osssrc->device_name); + + G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (osssrc)); +} + +static GstCaps * +gst_oss_src_getcaps (GstBaseSrc * bsrc) +{ + GstOssSrc *osssrc; + GstCaps *caps; + + osssrc = GST_OSS_SRC (bsrc); + + if (osssrc->fd == -1) { + GST_DEBUG_OBJECT (osssrc, "device not open, using template caps"); + return NULL; /* base class will get template caps for us */ + } + + if (osssrc->probed_caps) { + GST_LOG_OBJECT (osssrc, "Returning cached caps"); + return gst_caps_ref (osssrc->probed_caps); + } + + caps = gst_oss_helper_probe_caps (osssrc->fd); + + if (caps) { + osssrc->probed_caps = gst_caps_ref (caps); + } + + GST_INFO_OBJECT (osssrc, "returning caps %" GST_PTR_FORMAT, caps); + + return caps; +} + +static gint +ilog2 (gint x) +{ + /* well... hacker's delight explains... */ + x = x | (x >> 1); + x = x | (x >> 2); + x = x | (x >> 4); + x = x | (x >> 8); + x = x | (x >> 16); + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0f0f0f0f; + x = x + (x >> 8); + x = x + (x >> 16); + return (x & 0x0000003f) - 1; +} + +static gint +gst_oss_src_get_format (GstBufferFormat fmt) +{ + gint result; + + switch (fmt) { + case GST_MU_LAW: + result = AFMT_MU_LAW; + break; + case GST_A_LAW: + result = AFMT_A_LAW; + break; + case GST_IMA_ADPCM: + result = AFMT_IMA_ADPCM; + break; + case GST_U8: + result = AFMT_U8; + break; + case GST_S16_LE: + result = AFMT_S16_LE; + break; + case GST_S16_BE: + result = AFMT_S16_BE; + break; + case GST_S8: + result = AFMT_S8; + break; + case GST_U16_LE: + result = AFMT_U16_LE; + break; + case GST_U16_BE: + result = AFMT_U16_BE; + break; + case GST_MPEG: + result = AFMT_MPEG; + break; + default: + result = 0; + break; + } + return result; +} + +static gboolean +gst_oss_src_open (GstAudioSrc * asrc) +{ + GstOssSrc *oss; + int mode; + + oss = GST_OSS_SRC (asrc); + + mode = O_RDONLY; + mode |= O_NONBLOCK; + + oss->fd = open (oss->device, mode, 0); + if (oss->fd == -1) { + switch (errno) { + case EACCES: + goto no_permission; + default: + goto open_failed; + } + } + + if (!oss->mixer) { + oss->mixer = gst_ossmixer_new ("/dev/mixer", GST_OSS_MIXER_CAPTURE); + + if (oss->mixer) { + g_free (oss->device_name); + oss->device_name = g_strdup (oss->mixer->cardname); + } + } + return TRUE; + +no_permission: + { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ, + (_("Could not open audio device for recording. " + "You don't have permission to open the device.")), + GST_ERROR_SYSTEM); + return FALSE; + } +open_failed: + { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ, + (_("Could not open audio device for recording.")), + ("Unable to open device %s for recording: %s", + oss->device, g_strerror (errno))); + return FALSE; + } +} + +static gboolean +gst_oss_src_close (GstAudioSrc * asrc) +{ + GstOssSrc *oss; + + oss = GST_OSS_SRC (asrc); + + close (oss->fd); + + if (oss->mixer) { + gst_ossmixer_free (oss->mixer); + oss->mixer = NULL; + } + + gst_caps_replace (&oss->probed_caps, NULL); + + return TRUE; +} + +static gboolean +gst_oss_src_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec) +{ + GstOssSrc *oss; + struct audio_buf_info info; + int mode; + int fmt, tmp; + + oss = GST_OSS_SRC (asrc); + + mode = fcntl (oss->fd, F_GETFL); + mode &= ~O_NONBLOCK; + if (fcntl (oss->fd, F_SETFL, mode) == -1) + goto non_block; + + fmt = gst_oss_src_get_format (spec->format); + if (fmt == 0) + goto wrong_format; + + tmp = ilog2 (spec->segsize); + tmp = ((spec->segtotal & 0x7fff) << 16) | tmp; + GST_DEBUG_OBJECT (oss, "set segsize: %d, segtotal: %d, value: %08x", + spec->segsize, spec->segtotal, tmp); + + SET_PARAM (oss, SNDCTL_DSP_SETFRAGMENT, tmp, "SETFRAGMENT"); + + SET_PARAM (oss, SNDCTL_DSP_RESET, 0, "RESET"); + + SET_PARAM (oss, SNDCTL_DSP_SETFMT, fmt, "SETFMT"); + if (spec->channels == 2) + SET_PARAM (oss, SNDCTL_DSP_STEREO, 1, "STEREO"); + SET_PARAM (oss, SNDCTL_DSP_CHANNELS, spec->channels, "CHANNELS"); + SET_PARAM (oss, SNDCTL_DSP_SPEED, spec->rate, "SPEED"); + + GET_PARAM (oss, SNDCTL_DSP_GETISPACE, &info, "GETISPACE"); + + spec->segsize = info.fragsize; + spec->segtotal = info.fragstotal; + + if (spec->width != 16 && spec->width != 8) + goto dodgy_width; + + spec->bytes_per_sample = (spec->width / 8) * spec->channels; + oss->bytes_per_sample = (spec->width / 8) * spec->channels; + memset (spec->silence_sample, 0, spec->bytes_per_sample); + + GST_DEBUG_OBJECT (oss, "got segsize: %d, segtotal: %d, value: %08x", + spec->segsize, spec->segtotal, tmp); + + return TRUE; + +non_block: + { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ, + ("Unable to set device %s in non blocking mode: %s", + oss->device, g_strerror (errno)), (NULL)); + return FALSE; + } +wrong_format: + { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ, + ("Unable to get format %d", spec->format), (NULL)); + return FALSE; + } +dodgy_width: + { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ, + ("Unexpected width %d", spec->width), (NULL)); + return FALSE; + } +} + +static gboolean +gst_oss_src_unprepare (GstAudioSrc * asrc) +{ + /* could do a SNDCTL_DSP_RESET, but the OSS manual recommends a close/open */ + + if (!gst_oss_src_close (asrc)) + goto couldnt_close; + + if (!gst_oss_src_open (asrc)) + goto couldnt_reopen; + + return TRUE; + +couldnt_close: + { + GST_DEBUG_OBJECT (asrc, "Could not close the audio device"); + return FALSE; + } +couldnt_reopen: + { + GST_DEBUG_OBJECT (asrc, "Could not reopen the audio device"); + return FALSE; + } +} + +static guint +gst_oss_src_read (GstAudioSrc * asrc, gpointer data, guint length) +{ + return read (GST_OSS_SRC (asrc)->fd, data, length); +} + +static guint +gst_oss_src_delay (GstAudioSrc * asrc) +{ + GstOssSrc *oss; + gint delay = 0; + gint ret; + + oss = GST_OSS_SRC (asrc); + +#ifdef SNDCTL_DSP_GETODELAY + ret = ioctl (oss->fd, SNDCTL_DSP_GETODELAY, &delay); +#else + ret = -1; +#endif + if (ret < 0) { + audio_buf_info info; + + ret = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &info); + + delay = (ret < 0 ? 0 : (info.fragstotal * info.fragsize) - info.bytes); + } + return delay / oss->bytes_per_sample; +} + +static void +gst_oss_src_reset (GstAudioSrc * asrc) +{ + /* There's nothing we can do here really: OSS can't handle access to the + * same device/fd from multiple threads and might deadlock or blow up in + * other ways if we try an ioctl SNDCTL_DSP_RESET or similar */ +} diff --git a/sys/oss/gstosssrc.h b/sys/oss/gstosssrc.h new file mode 100644 index 0000000..0d14613 --- /dev/null +++ b/sys/oss/gstosssrc.h @@ -0,0 +1,67 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> + * 2000 Wim Taymans <wtay@chello.be> + * + * gstosssrc.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_OSS_SRC_H__ +#define __GST_OSS_SRC_H__ + + +#include <gst/gst.h> +#include <gst/audio/gstaudiosrc.h> + +#include "gstosshelper.h" +#include "gstossmixer.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OSS_SRC (gst_oss_src_get_type()) +#define GST_OSS_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS_SRC,GstOssSrc)) +#define GST_OSS_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS_SRC,GstOssSrcClass)) +#define GST_IS_OSS_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS_SRC)) +#define GST_IS_OSS_SRC_CLASS(klas) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS_SRC)) + +typedef struct _GstOssSrc GstOssSrc; +typedef struct _GstOssSrcClass GstOssSrcClass; + +struct _GstOssSrc { + GstAudioSrc src; + + gint fd; + gint bytes_per_sample; + + gchar *device; + gchar *device_name; + + GstCaps *probed_caps; + + GstOssMixer *mixer; +}; + +struct _GstOssSrcClass { + GstAudioSrcClass parent_class; +}; + +GType gst_oss_src_get_type(void); + +G_END_DECLS + +#endif /* __GST_OSS_SRC_H__ */ diff --git a/sys/oss4/Makefile.am b/sys/oss4/Makefile.am new file mode 100644 index 0000000..955e903 --- /dev/null +++ b/sys/oss4/Makefile.am @@ -0,0 +1,33 @@ +plugin_LTLIBRARIES = libgstoss4audio.la + +libgstoss4audio_la_SOURCES = \ + oss4-audio.c \ + oss4-mixer.c \ + oss4-mixer-enum.c \ + oss4-mixer-slider.c \ + oss4-mixer-switch.c \ + oss4-property-probe.c \ + oss4-sink.c \ + oss4-source.c + +libgstoss4audio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstoss4audio_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstinterfaces-$(GST_MAJORMINOR) \ + -lgstaudio-$(GST_MAJORMINOR) \ + $(GST_LIBS) +libgstoss4audio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstoss4audio_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = \ + oss4-audio.h \ + oss4-mixer.h \ + oss4-mixer-enum.h \ + oss4-mixer-slider.h \ + oss4-mixer-switch.h \ + oss4-property-probe.h \ + oss4-sink.h \ + oss4-soundcard.h \ + oss4-source.h + + diff --git a/sys/oss4/Makefile.in b/sys/oss4/Makefile.in new file mode 100644 index 0000000..3cda65b --- /dev/null +++ b/sys/oss4/Makefile.in @@ -0,0 +1,892 @@ +# 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 = sys/oss4 +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 = +libgstoss4audio_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_libgstoss4audio_la_OBJECTS = libgstoss4audio_la-oss4-audio.lo \ + libgstoss4audio_la-oss4-mixer.lo \ + libgstoss4audio_la-oss4-mixer-enum.lo \ + libgstoss4audio_la-oss4-mixer-slider.lo \ + libgstoss4audio_la-oss4-mixer-switch.lo \ + libgstoss4audio_la-oss4-property-probe.lo \ + libgstoss4audio_la-oss4-sink.lo \ + libgstoss4audio_la-oss4-source.lo +libgstoss4audio_la_OBJECTS = $(am_libgstoss4audio_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +libgstoss4audio_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) \ + $(libgstoss4audio_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 = $(libgstoss4audio_la_SOURCES) +DIST_SOURCES = $(libgstoss4audio_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 = libgstoss4audio.la +libgstoss4audio_la_SOURCES = \ + oss4-audio.c \ + oss4-mixer.c \ + oss4-mixer-enum.c \ + oss4-mixer-slider.c \ + oss4-mixer-switch.c \ + oss4-property-probe.c \ + oss4-sink.c \ + oss4-source.c + +libgstoss4audio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstoss4audio_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstinterfaces-$(GST_MAJORMINOR) \ + -lgstaudio-$(GST_MAJORMINOR) \ + $(GST_LIBS) + +libgstoss4audio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstoss4audio_la_LIBTOOLFLAGS = --tag=disable-static +noinst_HEADERS = \ + oss4-audio.h \ + oss4-mixer.h \ + oss4-mixer-enum.h \ + oss4-mixer-slider.h \ + oss4-mixer-switch.h \ + oss4-property-probe.h \ + oss4-sink.h \ + oss4-soundcard.h \ + oss4-source.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 sys/oss4/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu sys/oss4/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 +libgstoss4audio.la: $(libgstoss4audio_la_OBJECTS) $(libgstoss4audio_la_DEPENDENCIES) $(EXTRA_libgstoss4audio_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgstoss4audio_la_LINK) -rpath $(plugindir) $(libgstoss4audio_la_OBJECTS) $(libgstoss4audio_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstoss4audio_la-oss4-audio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstoss4audio_la-oss4-mixer-enum.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstoss4audio_la-oss4-mixer-slider.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstoss4audio_la-oss4-mixer-switch.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstoss4audio_la-oss4-mixer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstoss4audio_la-oss4-property-probe.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstoss4audio_la-oss4-sink.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstoss4audio_la-oss4-source.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 $@ $< + +libgstoss4audio_la-oss4-audio.lo: oss4-audio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -MT libgstoss4audio_la-oss4-audio.lo -MD -MP -MF $(DEPDIR)/libgstoss4audio_la-oss4-audio.Tpo -c -o libgstoss4audio_la-oss4-audio.lo `test -f 'oss4-audio.c' || echo '$(srcdir)/'`oss4-audio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstoss4audio_la-oss4-audio.Tpo $(DEPDIR)/libgstoss4audio_la-oss4-audio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oss4-audio.c' object='libgstoss4audio_la-oss4-audio.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 $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -c -o libgstoss4audio_la-oss4-audio.lo `test -f 'oss4-audio.c' || echo '$(srcdir)/'`oss4-audio.c + +libgstoss4audio_la-oss4-mixer.lo: oss4-mixer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -MT libgstoss4audio_la-oss4-mixer.lo -MD -MP -MF $(DEPDIR)/libgstoss4audio_la-oss4-mixer.Tpo -c -o libgstoss4audio_la-oss4-mixer.lo `test -f 'oss4-mixer.c' || echo '$(srcdir)/'`oss4-mixer.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstoss4audio_la-oss4-mixer.Tpo $(DEPDIR)/libgstoss4audio_la-oss4-mixer.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oss4-mixer.c' object='libgstoss4audio_la-oss4-mixer.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 $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -c -o libgstoss4audio_la-oss4-mixer.lo `test -f 'oss4-mixer.c' || echo '$(srcdir)/'`oss4-mixer.c + +libgstoss4audio_la-oss4-mixer-enum.lo: oss4-mixer-enum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -MT libgstoss4audio_la-oss4-mixer-enum.lo -MD -MP -MF $(DEPDIR)/libgstoss4audio_la-oss4-mixer-enum.Tpo -c -o libgstoss4audio_la-oss4-mixer-enum.lo `test -f 'oss4-mixer-enum.c' || echo '$(srcdir)/'`oss4-mixer-enum.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstoss4audio_la-oss4-mixer-enum.Tpo $(DEPDIR)/libgstoss4audio_la-oss4-mixer-enum.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oss4-mixer-enum.c' object='libgstoss4audio_la-oss4-mixer-enum.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 $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -c -o libgstoss4audio_la-oss4-mixer-enum.lo `test -f 'oss4-mixer-enum.c' || echo '$(srcdir)/'`oss4-mixer-enum.c + +libgstoss4audio_la-oss4-mixer-slider.lo: oss4-mixer-slider.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -MT libgstoss4audio_la-oss4-mixer-slider.lo -MD -MP -MF $(DEPDIR)/libgstoss4audio_la-oss4-mixer-slider.Tpo -c -o libgstoss4audio_la-oss4-mixer-slider.lo `test -f 'oss4-mixer-slider.c' || echo '$(srcdir)/'`oss4-mixer-slider.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstoss4audio_la-oss4-mixer-slider.Tpo $(DEPDIR)/libgstoss4audio_la-oss4-mixer-slider.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oss4-mixer-slider.c' object='libgstoss4audio_la-oss4-mixer-slider.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 $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -c -o libgstoss4audio_la-oss4-mixer-slider.lo `test -f 'oss4-mixer-slider.c' || echo '$(srcdir)/'`oss4-mixer-slider.c + +libgstoss4audio_la-oss4-mixer-switch.lo: oss4-mixer-switch.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -MT libgstoss4audio_la-oss4-mixer-switch.lo -MD -MP -MF $(DEPDIR)/libgstoss4audio_la-oss4-mixer-switch.Tpo -c -o libgstoss4audio_la-oss4-mixer-switch.lo `test -f 'oss4-mixer-switch.c' || echo '$(srcdir)/'`oss4-mixer-switch.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstoss4audio_la-oss4-mixer-switch.Tpo $(DEPDIR)/libgstoss4audio_la-oss4-mixer-switch.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oss4-mixer-switch.c' object='libgstoss4audio_la-oss4-mixer-switch.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 $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -c -o libgstoss4audio_la-oss4-mixer-switch.lo `test -f 'oss4-mixer-switch.c' || echo '$(srcdir)/'`oss4-mixer-switch.c + +libgstoss4audio_la-oss4-property-probe.lo: oss4-property-probe.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -MT libgstoss4audio_la-oss4-property-probe.lo -MD -MP -MF $(DEPDIR)/libgstoss4audio_la-oss4-property-probe.Tpo -c -o libgstoss4audio_la-oss4-property-probe.lo `test -f 'oss4-property-probe.c' || echo '$(srcdir)/'`oss4-property-probe.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstoss4audio_la-oss4-property-probe.Tpo $(DEPDIR)/libgstoss4audio_la-oss4-property-probe.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oss4-property-probe.c' object='libgstoss4audio_la-oss4-property-probe.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 $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -c -o libgstoss4audio_la-oss4-property-probe.lo `test -f 'oss4-property-probe.c' || echo '$(srcdir)/'`oss4-property-probe.c + +libgstoss4audio_la-oss4-sink.lo: oss4-sink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -MT libgstoss4audio_la-oss4-sink.lo -MD -MP -MF $(DEPDIR)/libgstoss4audio_la-oss4-sink.Tpo -c -o libgstoss4audio_la-oss4-sink.lo `test -f 'oss4-sink.c' || echo '$(srcdir)/'`oss4-sink.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstoss4audio_la-oss4-sink.Tpo $(DEPDIR)/libgstoss4audio_la-oss4-sink.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oss4-sink.c' object='libgstoss4audio_la-oss4-sink.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 $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -c -o libgstoss4audio_la-oss4-sink.lo `test -f 'oss4-sink.c' || echo '$(srcdir)/'`oss4-sink.c + +libgstoss4audio_la-oss4-source.lo: oss4-source.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -MT libgstoss4audio_la-oss4-source.lo -MD -MP -MF $(DEPDIR)/libgstoss4audio_la-oss4-source.Tpo -c -o libgstoss4audio_la-oss4-source.lo `test -f 'oss4-source.c' || echo '$(srcdir)/'`oss4-source.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstoss4audio_la-oss4-source.Tpo $(DEPDIR)/libgstoss4audio_la-oss4-source.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='oss4-source.c' object='libgstoss4audio_la-oss4-source.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 $(libgstoss4audio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstoss4audio_la_CFLAGS) $(CFLAGS) -c -o libgstoss4audio_la-oss4-source.lo `test -f 'oss4-source.c' || echo '$(srcdir)/'`oss4-source.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/sys/oss4/oss4-audio.c b/sys/oss4/oss4-audio.c new file mode 100644 index 0000000..09f8495 --- /dev/null +++ b/sys/oss4/oss4-audio.c @@ -0,0 +1,714 @@ +/* GStreamer OSS4 audio plugin + * Copyright (C) 2007-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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> + +#include "gst/gst-i18n-plugin.h" +#include <gst/audio/multichannel.h> + +#include "oss4-audio.h" +#include "oss4-mixer.h" +#include "oss4-property-probe.h" +#include "oss4-sink.h" +#include "oss4-source.h" +#include "oss4-soundcard.h" + +GST_DEBUG_CATEGORY (oss4mixer_debug); +GST_DEBUG_CATEGORY (oss4sink_debug); +GST_DEBUG_CATEGORY (oss4src_debug); +GST_DEBUG_CATEGORY (oss4_debug); + +#define GST_CAT_DEFAULT oss4_debug + +typedef struct +{ + const GstBufferFormat gst_fmt; + const gint oss_fmt; + const gchar name[16]; + const gint depth; + const gint width; + const gint endianness; + const gboolean signedness; +} GstOss4AudioFormat; + +/* *INDENT-OFF* */ +static const GstOss4AudioFormat fmt_map[] = { + /* note: keep sorted by preference, prefered formats first */ + { + GST_MU_LAW, AFMT_MU_LAW, "audio/x-mulaw", 0, 0, 0, FALSE}, { + GST_A_LAW, AFMT_A_LAW, "audio/x-alaw", 0, 0, 0, FALSE}, { + GST_S32_LE, AFMT_S32_LE, "audio/x-raw-int", 32, 32, G_LITTLE_ENDIAN, TRUE}, { + GST_S32_BE, AFMT_S32_BE, "audio/x-raw-int", 32, 32, G_BIG_ENDIAN, TRUE}, { + GST_S24_LE, AFMT_S24_LE, "audio/x-raw-int", 24, 32, G_LITTLE_ENDIAN, TRUE}, { + GST_S24_BE, AFMT_S24_BE, "audio/x-raw-int", 24, 32, G_BIG_ENDIAN, TRUE}, { + GST_S24_3LE, AFMT_S24_PACKED, "audio/x-raw-int", 24, 24, G_LITTLE_ENDIAN, + TRUE}, { + GST_S16_LE, AFMT_S16_LE, "audio/x-raw-int", 16, 16, G_LITTLE_ENDIAN, TRUE}, { + GST_S16_BE, AFMT_S16_BE, "audio/x-raw-int", 16, 16, G_BIG_ENDIAN, TRUE}, { + GST_U16_LE, AFMT_U16_LE, "audio/x-raw-int", 16, 16, G_LITTLE_ENDIAN, FALSE}, { + GST_U16_BE, AFMT_U16_BE, "audio/x-raw-int", 16, 16, G_BIG_ENDIAN, FALSE}, { + GST_S8, AFMT_S8, "audio/x-raw-int", 8, 8, 0, TRUE}, { + GST_U8, AFMT_U8, "audio/x-raw-int", 8, 8, 0, FALSE} +}; +/* *INDENT-ON* */ + +/* formats we assume the OSS4 layer can always handle and convert internally */ +#define CONVERTIBLE_FORMATS ( \ + AFMT_MU_LAW | AFMT_A_LAW | \ + AFMT_S32_LE | AFMT_S32_BE | \ + AFMT_S24_LE | AFMT_S24_BE | \ + AFMT_S24_PACKED | \ + AFMT_S16_LE | AFMT_S16_BE | \ + AFMT_U16_LE | AFMT_U16_BE | \ + AFMT_S8 | AFMT_U8 ) + +static void +gst_oss4_append_format_to_caps (const GstOss4AudioFormat * fmt, GstCaps * caps) +{ + GstStructure *s; + + s = gst_structure_empty_new (fmt->name); + if (fmt->width != 0 && fmt->depth != 0) { + gst_structure_set (s, "width", G_TYPE_INT, fmt->width, "depth", G_TYPE_INT, + fmt->depth, "signed", G_TYPE_BOOLEAN, fmt->signedness, NULL); + } + if (fmt->endianness != 0) { + gst_structure_set (s, "endianness", G_TYPE_INT, fmt->endianness, NULL); + } + gst_caps_append_structure (caps, s); +} + +static gint +gst_oss4_audio_get_oss_format (GstBufferFormat fmt) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) { + if (fmt_map[i].gst_fmt == fmt) + return fmt_map[i].oss_fmt; + } + return 0; +} + +/* These are pretty random */ +#define GST_OSS4_MIN_SAMPLE_RATE 1 +#define GST_OSS4_MAX_SAMPLE_RATE 192000 + +static gboolean +gst_oss4_audio_detect_rates (GstObject * obj, oss_audioinfo * ai, + GstCaps * caps) +{ + GValue val = { 0, }; + int minrate, maxrate, i; + + minrate = ai->min_rate; + maxrate = ai->max_rate; + + /* sanity check */ + if (minrate > maxrate) { + GST_WARNING_OBJECT (obj, "min_rate %d > max_rate %d (buggy driver?)", + minrate, maxrate); + maxrate = ai->min_rate; /* swap */ + minrate = ai->max_rate; + } + + /* limit to something sensible */ + if (minrate < GST_OSS4_MIN_SAMPLE_RATE) + minrate = GST_OSS4_MIN_SAMPLE_RATE; + if (maxrate > GST_OSS4_MAX_SAMPLE_RATE) + maxrate = GST_OSS4_MAX_SAMPLE_RATE; + + if (maxrate < GST_OSS4_MIN_SAMPLE_RATE) { + GST_WARNING_OBJECT (obj, "max_rate < %d, which makes no sense", + GST_OSS4_MIN_SAMPLE_RATE); + return FALSE; + } + + GST_LOG_OBJECT (obj, "min_rate %d, max_rate %d (originally: %d, %d)", + minrate, maxrate, ai->min_rate, ai->max_rate); + + if ((ai->caps & PCM_CAP_FREERATE)) { + GST_LOG_OBJECT (obj, "device supports any sample rate between min and max"); + if (minrate == maxrate) { + g_value_init (&val, G_TYPE_INT); + g_value_set_int (&val, maxrate); + } else { + g_value_init (&val, GST_TYPE_INT_RANGE); + gst_value_set_int_range (&val, minrate, maxrate); + } + } else { + GST_LOG_OBJECT (obj, "%d sample rates:", ai->nrates); + g_value_init (&val, GST_TYPE_LIST); + for (i = 0; i < ai->nrates; ++i) { + GST_LOG_OBJECT (obj, " rate: %d", ai->rates[i]); + + if (ai->rates[i] >= minrate && ai->rates[i] <= maxrate) { + GValue rate_val = { 0, }; + + g_value_init (&rate_val, G_TYPE_INT); + g_value_set_int (&rate_val, ai->rates[i]); + gst_value_list_append_value (&val, &rate_val); + g_value_unset (&rate_val); + } + } + + if (gst_value_list_get_size (&val) == 0) { + g_value_unset (&val); + return FALSE; + } + } + + for (i = 0; i < gst_caps_get_size (caps); ++i) { + GstStructure *s; + + s = gst_caps_get_structure (caps, i); + gst_structure_set_value (s, "rate", &val); + } + + g_value_unset (&val); + + return TRUE; +} + +static void +gst_oss4_audio_add_channel_layout (GstObject * obj, guint64 layout, + guint num_channels, GstStructure * s) +{ + const GstAudioChannelPosition pos_map[16] = { + GST_AUDIO_CHANNEL_POSITION_NONE, /* 0 = dunno */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, /* 1 = left */ + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, /* 2 = right */ + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, /* 3 = center */ + GST_AUDIO_CHANNEL_POSITION_LFE, /* 4 = lfe */ + GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, /* 5 = left surround */ + GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, /* 6 = right surround */ + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, /* 7 = left rear */ + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, /* 8 = right rear */ + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE + }; + GstAudioChannelPosition ch_layout[8] = { 0, }; + guint speaker_pos; /* speaker position as defined by OSS */ + guint i; + + g_return_if_fail (num_channels <= G_N_ELEMENTS (ch_layout)); + + for (i = 0; i < num_channels; ++i) { + /* layout contains up to 16 speaker positions, with each taking up 4 bits */ + speaker_pos = (guint) ((layout >> (i * 4)) & 0x0f); + + /* if it's a channel position that's unknown to us, set all to NONE and + * bail out */ + if (G_UNLIKELY (pos_map[speaker_pos] == GST_AUDIO_CHANNEL_POSITION_NONE)) + goto no_layout; + + ch_layout[i] = pos_map[speaker_pos]; + } + gst_audio_set_channel_positions (s, ch_layout); + return; + +no_layout: + { + /* only warn if it's really unknown, position 0 is ok and represents NONE + * (in which case we also just set all others to NONE ignoring the other + * positions in the OSS-given layout, because that's what we currently + * require in GStreamer) */ + if (speaker_pos != 0) { + GST_WARNING_OBJECT (obj, "unknown OSS channel position %x", ch_layout[i]); + } + for (i = 0; i < num_channels; ++i) { + ch_layout[i] = GST_AUDIO_CHANNEL_POSITION_NONE; + } + gst_audio_set_channel_positions (s, ch_layout); + return; + } +} + +/* arbitrary max. limit */ +#define GST_OSS4_MIN_CHANNELS 1 +#define GST_OSS4_MAX_CHANNELS 4096 + +/* takes ownership of the input caps */ +static GstCaps * +gst_oss4_audio_detect_channels (GstObject * obj, int fd, oss_audioinfo * ai, + GstCaps * in_caps) +{ + const gchar *forced_layout; + GstStructure *s = NULL; + guint64 layout = 0; + GstCaps *chan_caps = NULL; + GstCaps *out_caps = NULL; + int minchans, maxchans; + int c, i, j; + + /* GST_OSS4_CHANNEL_LAYOUT environment variable: may be used to force a + * particular channel layout (if it contains an odd number of channel + * positions it will also make us advertise a channel layout for that + * channel count, even if we'd usually skip it; this is especially useful + * for folks with 2.1 speakers, I guess) */ + forced_layout = g_getenv ("GST_OSS4_CHANNEL_LAYOUT"); + + minchans = ai->min_channels; + maxchans = ai->max_channels; + + /* sanity check */ + if (minchans > maxchans) { + GST_WARNING_OBJECT (obj, "min_chans %d > max_chans %d (buggy driver?)", + minchans, maxchans); + maxchans = ai->min_channels; /* swap */ + minchans = ai->max_channels; + } + + /* limit to something sensible */ + if (minchans < GST_OSS4_MIN_CHANNELS) + minchans = GST_OSS4_MIN_CHANNELS; + if (maxchans > GST_OSS4_MAX_CHANNELS) + maxchans = GST_OSS4_MAX_CHANNELS; + + if (maxchans < GST_OSS4_MIN_CHANNELS) { + GST_WARNING_OBJECT (obj, "max_chans < %d, which makes no sense", + GST_OSS4_MIN_CHANNELS); + gst_caps_unref (in_caps); + return NULL; + } + + GST_LOG_OBJECT (obj, "min_channels %d, max_channels %d (originally: %d, %d)", + minchans, maxchans, ai->min_channels, ai->max_channels); + + chan_caps = gst_caps_new_empty (); + + /* first do the simple cases: mono + stereo (channel layout implied) */ + if (minchans == 1 && maxchans == 1) + s = gst_structure_new ("x", "channels", G_TYPE_INT, 1, NULL); + else if (minchans == 2 && maxchans >= 2) + s = gst_structure_new ("x", "channels", G_TYPE_INT, 2, NULL); + else if (minchans == 1 && maxchans >= 2) + s = gst_structure_new ("x", "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); + gst_caps_append_structure (chan_caps, s); + s = NULL; + + /* TODO: we assume all drivers use a left/right layout for stereo here */ + if (maxchans <= 2) + goto done; + + if (ioctl (fd, SNDCTL_DSP_GET_CHNORDER, &layout) == -1) { + GST_WARNING_OBJECT (obj, "couldn't query channel layout, assuming default"); + layout = CHNORDER_NORMAL; + } + GST_DEBUG_OBJECT (obj, "channel layout: %08" G_GINT64_MODIFIER "x", layout); + + /* e.g. forced 2.1 layout would be GST_OSS4_CHANNEL_LAYOUT=421 */ + if (forced_layout != NULL && *forced_layout != '\0') { + guint layout_len; + + layout_len = strlen (forced_layout); + if (layout_len >= minchans && layout_len <= maxchans) { + layout = g_ascii_strtoull (forced_layout, NULL, 16); + maxchans = layout_len; + GST_DEBUG_OBJECT (obj, "forced channel layout: %08" G_GINT64_MODIFIER "x" + " ('%s'), maxchans now %d", layout, forced_layout, maxchans); + } else { + GST_WARNING_OBJECT (obj, "ignoring forced channel layout: layout has %d " + "channel positions but maxchans is %d", layout_len, maxchans); + } + } + + /* need to advertise channel layouts for anything >2 and <=8 channels */ + for (c = MAX (3, minchans); c <= MIN (maxchans, 8); c++) { + /* "The min_channels and max_channels fields define the limits for the + * number of channels. However some devices don't support all channels + * within this range. It's possible that the odd values (3, 5, 7, 9, etc). + * are not supported. There is currently no way to check for this other + * than checking if SNDCTL_DSP_CHANNELS accepts the requested value. + * Another approach is trying to avoid using odd number of channels." + * + * So, we don't know for sure if these odd values are supported: + */ + if ((c == 3 || c == 5 || c == 7) && (c != maxchans)) { + GST_LOG_OBJECT (obj, "not adding layout with %d channels", c); + continue; + } + + s = gst_structure_new ("x", "channels", G_TYPE_INT, c, NULL); + gst_oss4_audio_add_channel_layout (obj, layout, c, s); + GST_LOG_OBJECT (obj, "c=%u, appending struct %" GST_PTR_FORMAT, c, s); + gst_caps_append_structure (chan_caps, s); + s = NULL; + } + + if (maxchans <= 8) + goto done; + + /* for everything >8 channels, CHANNEL_POSITION_NONE is implied. */ + if (minchans == maxchans || maxchans == 9) { + s = gst_structure_new ("x", "channels", G_TYPE_INT, maxchans, NULL); + } else { + s = gst_structure_new ("x", "channels", GST_TYPE_INT_RANGE, + MAX (9, minchans), maxchans, NULL); + } + gst_caps_append_structure (chan_caps, s); + s = NULL; + +done: + + GST_LOG_OBJECT (obj, "channel structures: %" GST_PTR_FORMAT, chan_caps); + + out_caps = gst_caps_new_empty (); + + /* combine each structure in the input caps with each channel caps struct */ + for (i = 0; i < gst_caps_get_size (in_caps); ++i) { + const GstStructure *in_s; + + in_s = gst_caps_get_structure (in_caps, i); + + for (j = 0; j < gst_caps_get_size (chan_caps); ++j) { + const GstStructure *chan_s; + const GValue *val; + + s = gst_structure_copy (in_s); + chan_s = gst_caps_get_structure (chan_caps, j); + if ((val = gst_structure_get_value (chan_s, "channels"))) + gst_structure_set_value (s, "channels", val); + if ((val = gst_structure_get_value (chan_s, "channel-positions"))) + gst_structure_set_value (s, "channel-positions", val); + + gst_caps_append_structure (out_caps, s); + s = NULL; + } + } + + gst_caps_unref (in_caps); + gst_caps_unref (chan_caps); + return out_caps; +} + +GstCaps * +gst_oss4_audio_probe_caps (GstObject * obj, int fd) +{ + oss_audioinfo ai = { 0, }; + gboolean output; + GstCaps *caps; + int nonnative_formats = 0; + int formats, i; + + output = GST_IS_OSS4_SINK (obj); + + /* -1 = get info for currently open device (fd). This will fail with + * OSS build <= 1013 because of a bug in OSS */ + ai.dev = -1; + if (ioctl (fd, SNDCTL_ENGINEINFO, &ai) == -1) + goto engineinfo_failed; + + formats = (output) ? ai.oformats : ai.iformats; + + GST_LOG_OBJECT (obj, "%s formats : 0x%08x", (output) ? "out" : "in", formats); + + caps = gst_caps_new_empty (); + + /* first list all the formats natively supported */ + for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) { + if ((formats & fmt_map[i].oss_fmt)) { + gst_oss4_append_format_to_caps (&fmt_map[i], caps); + } else if ((fmt_map[i].oss_fmt & CONVERTIBLE_FORMATS)) { + nonnative_formats |= fmt_map[i].oss_fmt; + } + } + + GST_LOG_OBJECT (obj, "adding non-native %s formats : 0x%08x", + (output) ? "out" : "in", nonnative_formats); + + /* now append non-native formats for which conversion would be needed */ + for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) { + if ((nonnative_formats & fmt_map[i].oss_fmt)) { + gst_oss4_append_format_to_caps (&fmt_map[i], caps); + } + } + + gst_caps_do_simplify (caps); + GST_LOG_OBJECT (obj, "formats: %" GST_PTR_FORMAT, caps); + + if (!gst_oss4_audio_detect_rates (obj, &ai, caps)) + goto detect_rates_failed; + + caps = gst_oss4_audio_detect_channels (obj, fd, &ai, caps); + if (caps == NULL) + goto detect_channels_failed; + + GST_LOG_OBJECT (obj, "probed caps: %" GST_PTR_FORMAT, caps); + + return caps; + +/* ERRORS */ +engineinfo_failed: + { + GST_WARNING ("ENGINEINFO supported formats probe failed: %s", + g_strerror (errno)); + return NULL; + } +detect_rates_failed: + { + GST_WARNING_OBJECT (obj, "failed to detect supported sample rates"); + gst_caps_unref (caps); + return NULL; + } +detect_channels_failed: + { + GST_WARNING_OBJECT (obj, "failed to detect supported channels"); + gst_caps_unref (caps); + return NULL; + } +} + +GstCaps * +gst_oss4_audio_get_template_caps (void) +{ + GstCaps *caps; + gint i; + + caps = gst_caps_new_empty (); + + for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) { + gst_oss4_append_format_to_caps (&fmt_map[i], caps); + } + + gst_caps_do_simplify (caps); + + for (i = 0; i < gst_caps_get_size (caps); ++i) { + GstStructure *s; + + s = gst_caps_get_structure (caps, i); + gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, GST_OSS4_MIN_SAMPLE_RATE, + GST_OSS4_MAX_SAMPLE_RATE, "channels", GST_TYPE_INT_RANGE, + GST_OSS4_MIN_CHANNELS, GST_OSS4_MAX_CHANNELS, NULL); + } + + return caps; +} + +/* called by gst_oss4_sink_prepare() and gst_oss4_source_prepare() */ +gboolean +gst_oss4_audio_set_format (GstObject * obj, int fd, GstRingBufferSpec * spec) +{ + struct audio_buf_info info = { 0, }; + int fmt, chans, rate; + + fmt = gst_oss4_audio_get_oss_format (spec->format); + if (fmt == 0) + goto wrong_format; + + if (spec->type == GST_BUFTYPE_LINEAR && spec->width != 32 && + spec->width != 24 && spec->width != 16 && spec->width != 8) { + goto dodgy_width; + } + + /* format */ + GST_LOG_OBJECT (obj, "setting format: %d", fmt); + if (ioctl (fd, SNDCTL_DSP_SETFMT, &fmt) == -1) + goto set_format_failed; + + /* channels */ + GST_LOG_OBJECT (obj, "setting channels: %d", spec->channels); + chans = spec->channels; + if (ioctl (fd, SNDCTL_DSP_CHANNELS, &chans) == -1) + goto set_channels_failed; + + /* rate */ + GST_LOG_OBJECT (obj, "setting rate: %d", spec->rate); + rate = spec->rate; + if (ioctl (fd, SNDCTL_DSP_SPEED, &rate) == -1) + goto set_rate_failed; + + GST_DEBUG_OBJECT (obj, "effective format : %d", fmt); + GST_DEBUG_OBJECT (obj, "effective channels : %d", chans); + GST_DEBUG_OBJECT (obj, "effective rate : %d", rate); + + /* make sure format, channels, and rate are the ones we requested */ + if (fmt != gst_oss4_audio_get_oss_format (spec->format) || + chans != spec->channels || rate != spec->rate) { + /* This shouldn't happen, but hey */ + goto format_not_what_was_requested; + } + + if (GST_IS_OSS4_SOURCE (obj)) { + if (ioctl (fd, SNDCTL_DSP_GETISPACE, &info) == -1) + goto get_ispace_failed; + } else { + if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &info) == -1) + goto get_ospace_failed; + } + + spec->segsize = info.fragsize; + + /* we add some extra fragments -- this helps us account for delays due to + * conversion buffer, streams queueing, etc. It is important that these + * be taken into account because otherwise the delay counter can wind up + * being too large, and the buffer will wrap. */ + spec->segtotal = info.fragstotal + 4; + + spec->bytes_per_sample = (spec->width / 8) * spec->channels; + + GST_DEBUG_OBJECT (obj, "got segsize: %d, segtotal: %d, value: %08x", + spec->segsize, spec->segtotal, info.fragsize); + + return TRUE; + +/* ERRORS */ +wrong_format: + { + GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL), + ("Unable to get format %d", spec->format)); + return FALSE; + } +dodgy_width: + { + GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL), + ("unexpected width %d", spec->width)); + return FALSE; + } +set_format_failed: + { + GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL), + ("DSP_SETFMT(%d) failed: %s", fmt, g_strerror (errno))); + return FALSE; + } +set_channels_failed: + { + GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL), + ("DSP_CHANNELS(%d) failed: %s", chans, g_strerror (errno))); + return FALSE; + } +set_rate_failed: + { + GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL), + ("DSP_SPEED(%d) failed: %s", rate, g_strerror (errno))); + return FALSE; + } +get_ospace_failed: + { + GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL), + ("DSP_GETOSPACE failed: %s", g_strerror (errno))); + return FALSE; + } +get_ispace_failed: + { + GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL), + ("DSP_GETISPACE failed: %s", g_strerror (errno))); + return FALSE; + } +format_not_what_was_requested: + { + GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL), + ("Format actually configured wasn't the one we requested. This is " + "probably either a bug in the driver or in the format probing code.")); + return FALSE; + } +} + +int +gst_oss4_audio_get_version (GstObject * obj, int fd) +{ + gint ver = 0; + + /* we use the old ioctl here on purpose instead of SNDCTL_SYSINFO */ + if (ioctl (fd, OSS_GETVERSION, &ver) < 0) { + GST_LOG_OBJECT (obj, "OSS_GETVERSION failed: %s", g_strerror (errno)); + return -1; + } + GST_LOG_OBJECT (obj, "OSS version: 0x%08x", ver); + return ver; +} + +gboolean +gst_oss4_audio_check_version (GstObject * obj, int fd) +{ + return (gst_oss4_audio_get_version (obj, fd) >= GST_MIN_OSS4_VERSION); +} + +gchar * +gst_oss4_audio_find_device (GstObject * oss) +{ + GValueArray *arr; + gchar *ret = NULL; + + arr = gst_property_probe_probe_and_get_values_name (GST_PROPERTY_PROBE (oss), + "device"); + + if (arr != NULL) { + if (arr->n_values > 0) { + const GValue *val; + + val = g_value_array_get_nth (arr, 0); + ret = g_value_dup_string (val); + } + g_value_array_free (arr); + } + + GST_LOG_OBJECT (oss, "first device found: %s", GST_STR_NULL (ret)); + + return ret; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + gint rank; + + GST_DEBUG_CATEGORY_INIT (oss4sink_debug, "oss4sink", 0, "OSS4 audio sink"); + GST_DEBUG_CATEGORY_INIT (oss4src_debug, "oss4src", 0, "OSS4 audio src"); + GST_DEBUG_CATEGORY_INIT (oss4mixer_debug, "oss4mixer", 0, "OSS4 mixer"); + GST_DEBUG_CATEGORY_INIT (oss4_debug, "oss4", 0, "OSS4 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 + + /* we want a higher rank than the legacy OSS elements have now */ + rank = GST_RANK_SECONDARY + 1; + + if (!gst_element_register (plugin, "oss4sink", rank, GST_TYPE_OSS4_SINK) || + !gst_element_register (plugin, "oss4src", rank, GST_TYPE_OSS4_SOURCE) || + !gst_element_register (plugin, "oss4mixer", rank, GST_TYPE_OSS4_MIXER)) { + return FALSE; + } + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "oss4", + "Open Sound System (OSS) version 4 support for GStreamer", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/oss4/oss4-audio.h b/sys/oss4/oss4-audio.h new file mode 100644 index 0000000..d220364 --- /dev/null +++ b/sys/oss4/oss4-audio.h @@ -0,0 +1,43 @@ +/* GStreamer OSS4 audio plugin + * Copyright (C) 2007-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_OSS4_AUDIO_H +#define GST_OSS4_AUDIO_H_ + +#include <gst/gst.h> +#include <gst/audio/gstringbuffer.h> + +/* This is the minimum version we require */ +#define GST_MIN_OSS4_VERSION 0x040003 + +int gst_oss4_audio_get_version (GstObject * obj, int fd); + +gboolean gst_oss4_audio_check_version (GstObject * obj, int fd); + +GstCaps * gst_oss4_audio_probe_caps (GstObject * obj, int fd); + +gboolean gst_oss4_audio_set_format (GstObject * obj, int fd, GstRingBufferSpec * spec); + +GstCaps * gst_oss4_audio_get_template_caps (void); + +gchar * gst_oss4_audio_find_device (GstObject * oss); + +#endif /* GST_OSS4_AUDIO_H */ + + diff --git a/sys/oss4/oss4-mixer-enum.c b/sys/oss4/oss4-mixer-enum.c new file mode 100644 index 0000000..4b64bb1 --- /dev/null +++ b/sys/oss4/oss4-mixer-enum.c @@ -0,0 +1,269 @@ +/* GStreamer OSS4 mixer enumeration control + * Copyright (C) 2007-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. + */ + +/* An 'enum' in gnome-volume-control / GstMixer is represented by a + * GstMixerOptions object + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gst/gst-i18n-plugin.h> + +#define NO_LEGACY_MIXER +#include "oss4-mixer.h" +#include "oss4-mixer-enum.h" +#include "oss4-soundcard.h" + +GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug); +#define GST_CAT_DEFAULT oss4mixer_debug + +static GList *gst_oss4_mixer_enum_get_values (GstMixerOptions * options); + +/* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */ +G_DEFINE_TYPE (GstOss4MixerEnum, gst_oss4_mixer_enum, GST_TYPE_MIXER_OPTIONS); + +static void +gst_oss4_mixer_enum_init (GstOss4MixerEnum * e) +{ + e->need_update = TRUE; +} + +static void +gst_oss4_mixer_enum_dispose (GObject * obj) +{ + GstMixerOptions *options = GST_MIXER_OPTIONS (obj); + + /* our list is a flat list with constant strings, but the GstMixerOptions + * dispose will try to g_free the contained strings, so clean up the list + * before chaining up to GstMixerOptions */ + g_list_free (options->values); + options->values = NULL; + + G_OBJECT_CLASS (gst_oss4_mixer_enum_parent_class)->dispose (obj); +} + +static void +gst_oss4_mixer_enum_class_init (GstOss4MixerEnumClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstMixerOptionsClass *mixeroptions_class = (GstMixerOptionsClass *) klass; + + gobject_class->dispose = gst_oss4_mixer_enum_dispose; + mixeroptions_class->get_values = gst_oss4_mixer_enum_get_values; +} + +static GList * +gst_oss4_mixer_enum_get_values_locked (GstMixerOptions * options) +{ + GstOss4MixerEnum *e = GST_OSS4_MIXER_ENUM_CAST (options); + GList *oldlist, *list = NULL; + int i; + + /* if current list of values is empty, update/re-check in any case */ + if (!e->need_update && options->values != NULL) + return options->values; + + GST_LOG_OBJECT (e, "updating available values for %s", e->mc->mixext.extname); + + for (i = 0; i < e->mc->mixext.maxvalue; ++i) { + const gchar *s; + + s = g_quark_to_string (e->mc->enum_vals[i]); + if (MIXEXT_ENUM_IS_AVAILABLE (e->mc->mixext, i)) { + GST_LOG_OBJECT (e, "option '%s' is available", s); + list = g_list_prepend (list, (gpointer) s); + } else { + GST_LOG_OBJECT (e, "option '%s' is currently not available", s); + } + } + + list = g_list_reverse (list); + + /* this is not thread-safe, but then the entire GstMixer API isn't really, + * since we return foo->list and not a copy and don't take any locks, so + * not much we can do here but pray; we're usually either called from _new() + * or from within _get_values() though, so it should be okay. We could use + * atomic ops here, but I'm not sure how much more that really buys us.*/ + oldlist = options->values; /* keep window small */ + options->values = list; + g_list_free (oldlist); + + e->need_update = FALSE; + + return options->values; +} + +static GList * +gst_oss4_mixer_enum_get_values (GstMixerOptions * options) +{ + GstOss4MixerEnum *e = GST_OSS4_MIXER_ENUM (options); + GList *list; + + /* we take the lock here mostly to serialise ioctls with the watch thread */ + GST_OBJECT_LOCK (e->mixer); + + list = gst_oss4_mixer_enum_get_values_locked (options); + + GST_OBJECT_UNLOCK (e->mixer); + + return list; +} + +static const gchar * +gst_oss4_mixer_enum_get_current_value (GstOss4MixerEnum * e) +{ + const gchar *cur_val = NULL; + + if (e->mc->enum_vals != NULL && e->mc->last_val < e->mc->mixext.maxvalue) { + cur_val = g_quark_to_string (e->mc->enum_vals[e->mc->last_val]); + } + + return cur_val; +} + +static gboolean +gst_oss4_mixer_enum_update_current (GstOss4MixerEnum * e) +{ + int cur = -1; + + if (!gst_oss4_mixer_get_control_val (e->mixer, e->mc, &cur)) + return FALSE; + + if (cur < 0 || cur >= e->mc->mixext.maxvalue) { + GST_WARNING_OBJECT (e, "read value %d out of bounds [0-%d]", cur, + e->mc->mixext.maxvalue - 1); + e->mc->last_val = 0; + return FALSE; + } + + return TRUE; +} + +gboolean +gst_oss4_mixer_enum_set_option (GstOss4MixerEnum * e, const gchar * value) +{ + GQuark q; + int i; + + q = g_quark_try_string (value); + if (q == 0) { + GST_WARNING_OBJECT (e, "unknown option '%s'", value); + return FALSE; + } + + for (i = 0; i < e->mc->mixext.maxvalue; ++i) { + if (q == e->mc->enum_vals[i]) + break; + } + + if (i >= e->mc->mixext.maxvalue) { + GST_WARNING_OBJECT (e, "option '%s' is not valid for this control", value); + return FALSE; + } + + GST_LOG_OBJECT (e, "option '%s' = %d", value, i); + + if (!MIXEXT_ENUM_IS_AVAILABLE (e->mc->mixext, i)) { + GST_WARNING_OBJECT (e, "option '%s' is not selectable currently", value); + return FALSE; + } + + if (!gst_oss4_mixer_set_control_val (e->mixer, e->mc, i)) { + GST_WARNING_OBJECT (e, "could not set option '%s' (%d)", value, i); + return FALSE; + } + + /* and re-read current value with sanity checks (or could just assign here) */ + gst_oss4_mixer_enum_update_current (e); + + return TRUE; +} + +const gchar * +gst_oss4_mixer_enum_get_option (GstOss4MixerEnum * e) +{ + const gchar *cur_str = NULL; + + if (!gst_oss4_mixer_enum_update_current (e)) { + GST_WARNING_OBJECT (e, "failed to read current value"); + return NULL; + } + + cur_str = gst_oss4_mixer_enum_get_current_value (e); + GST_LOG_OBJECT (e, "%s (%d)", GST_STR_NULL (cur_str), e->mc->last_val); + return cur_str; +} + +GstMixerTrack * +gst_oss4_mixer_enum_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc) +{ + GstOss4MixerEnum *e; + GstMixerTrack *track; + + e = g_object_new (GST_TYPE_OSS4_MIXER_ENUM, "untranslated-label", + mc->mixext.extname, NULL); + e->mixer = mixer; + e->mc = mc; + + track = GST_MIXER_TRACK (e); + + /* caller will set track->label and track->flags */ + + track->num_channels = 0; + track->min_volume = 0; + track->max_volume = 0; + + (void) gst_oss4_mixer_enum_get_values_locked (GST_MIXER_OPTIONS (track)); + + if (!gst_oss4_mixer_enum_update_current (e)) { + GST_WARNING_OBJECT (track, "failed to read current value, returning NULL"); + g_object_unref (track); + track = NULL; + } + + GST_LOG_OBJECT (e, "current value: %d (%s)", e->mc->last_val, + gst_oss4_mixer_enum_get_current_value (e)); + + return track; +} + +/* This is called from the watch thread */ +void +gst_oss4_mixer_enum_process_change_unlocked (GstMixerTrack * track) +{ + GstOss4MixerEnum *e = GST_OSS4_MIXER_ENUM_CAST (track); + + gchar *cur; + + if (!e->mc->changed && !e->mc->list_changed) + return; + + if (e->mc->list_changed) { + gst_mixer_options_list_changed (GST_MIXER (e->mixer), + GST_MIXER_OPTIONS (e)); + } + + GST_OBJECT_LOCK (e->mixer); + cur = (gchar *) gst_oss4_mixer_enum_get_current_value (e); + GST_OBJECT_UNLOCK (e->mixer); + + gst_mixer_option_changed (GST_MIXER (e->mixer), GST_MIXER_OPTIONS (e), cur); +} diff --git a/sys/oss4/oss4-mixer-enum.h b/sys/oss4/oss4-mixer-enum.h new file mode 100644 index 0000000..9fd8166 --- /dev/null +++ b/sys/oss4/oss4-mixer-enum.h @@ -0,0 +1,67 @@ +/* GStreamer OSS4 mixer on/off enum control + * Copyright (C) 2007-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_OSS4_MIXER_ENUM_H +#define GST_OSS4_MIXER_ENUM_H + +#include <gst/gst.h> +#include <gst/interfaces/mixer.h> + +#include "oss4-mixer.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OSS4_MIXER_ENUM (gst_oss4_mixer_enum_get_type()) +#define GST_OSS4_MIXER_ENUM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_MIXER_ENUM,GstOss4MixerEnum)) +#define GST_OSS4_MIXER_ENUM_CAST(obj) ((GstOss4MixerEnum *)(obj)) +#define GST_OSS4_MIXER_ENUM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_MIXER_ENUM,GstOss4MixerEnumClass)) +#define GST_IS_OSS4_MIXER_ENUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_MIXER_ENUM)) +#define GST_IS_OSS4_MIXER_ENUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_MIXER_ENUM)) + +typedef struct _GstOss4MixerEnum GstOss4MixerEnum; +typedef struct _GstOss4MixerEnumClass GstOss4MixerEnumClass; + +struct _GstOss4MixerEnum { + GstMixerOptions mixer_option; + + GstOss4MixerControl * mc; + GstOss4Mixer * mixer; /* the mixer we belong to (no ref taken) */ + + gboolean need_update; +}; + +struct _GstOss4MixerEnumClass { + GstMixerOptionsClass mixer_option_class; +}; + +GType gst_oss4_mixer_enum_get_type (void); + +gboolean gst_oss4_mixer_enum_set_option (GstOss4MixerEnum * e, const gchar * value); + +const gchar * gst_oss4_mixer_enum_get_option (GstOss4MixerEnum * e); + +GstMixerTrack * gst_oss4_mixer_enum_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc); + +void gst_oss4_mixer_enum_process_change_unlocked (GstMixerTrack * track); + +G_END_DECLS + +#endif /* GST_OSS4_MIXER_ENUM_H */ + + diff --git a/sys/oss4/oss4-mixer-slider.c b/sys/oss4/oss4-mixer-slider.c new file mode 100644 index 0000000..ea2bc8c --- /dev/null +++ b/sys/oss4/oss4-mixer-slider.c @@ -0,0 +1,311 @@ +/* GStreamer OSS4 mixer slider control + * Copyright (C) 2007-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. + */ + +/* A 'slider' in gnome-volume-control / GstMixer is represented by a + * GstMixerTrack with one or more channels. + * + * A slider should be either flagged as INPUT or OUTPUT (mostly because of + * gnome-volume-control being littered with g_asserts for everything it doesn't + * expect). + * + * From mixertrack.h: + * "Input tracks can have 'recording' enabled, which means that any input will + * be hearable into the speakers that are attached to the output. Mute is + * obvious." + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> + +#include <gst/gst-i18n-plugin.h> + +#define NO_LEGACY_MIXER +#include "oss4-mixer-slider.h" + +GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug); +#define GST_CAT_DEFAULT oss4mixer_debug + +/* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */ +G_DEFINE_TYPE (GstOss4MixerSlider, gst_oss4_mixer_slider, GST_TYPE_MIXER_TRACK); + +static void +gst_oss4_mixer_slider_class_init (GstOss4MixerSliderClass * klass) +{ + /* nothing to do here */ +} + +static void +gst_oss4_mixer_slider_init (GstOss4MixerSlider * s) +{ + /* nothing to do here */ +} + +static int +gst_oss4_mixer_slider_pack_volume (GstOss4MixerSlider * s, const gint * volumes) +{ + int val = 0; + + switch (s->mc->mixext.type) { + case MIXT_MONOSLIDER: + case MIXT_MONOSLIDER16: + case MIXT_SLIDER: + val = volumes[0]; + break; + case MIXT_STEREOSLIDER: + val = ((volumes[1] & 0xff) << 8) | (volumes[0] & 0xff); + break; + case MIXT_STEREOSLIDER16: + val = ((volumes[1] & 0xffff) << 16) | (volumes[0] & 0xffff); + break; + default: + g_return_val_if_reached (0); + } + return val; +} + +static void +gst_oss4_mixer_slider_unpack_volume (GstOss4MixerSlider * s, int v, + gint * volumes) +{ + guint32 val; /* use uint so bitshifting the highest bit works right */ + + val = (guint32) v; + switch (s->mc->mixext.type) { + case MIXT_SLIDER: + volumes[0] = val; + break; + case MIXT_MONOSLIDER: + /* oss repeats the value in the upper bits, as if it was stereo */ + volumes[0] = val & 0x00ff; + break; + case MIXT_MONOSLIDER16: + /* oss repeats the value in the upper bits, as if it was stereo */ + volumes[0] = val & 0x0000ffff; + break; + case MIXT_STEREOSLIDER: + volumes[0] = (val & 0x00ff); + volumes[1] = (val & 0xff00) >> 8; + break; + case MIXT_STEREOSLIDER16: + volumes[0] = (val & 0x0000ffff); + volumes[1] = (val & 0xffff0000) >> 16; + break; + default: + g_return_if_reached (); + } +} + +gboolean +gst_oss4_mixer_slider_get_volume (GstOss4MixerSlider * s, gint * volumes) +{ + GstMixerTrack *track = GST_MIXER_TRACK (s); + int v = 0; + + /* if we're supposed to be muted, and don't have an actual mute control + * (ie. 'simulate' the mute), then just return the volume as saved, not + * the actually set volume which is most likely 0 */ + if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE) && !s->mc->mute) { + volumes[0] = s->volumes[0]; + if (track->num_channels == 2) + volumes[1] = s->volumes[1]; + return TRUE; + } + + if (!gst_oss4_mixer_get_control_val (s->mixer, s->mc, &v)) + return FALSE; + + gst_oss4_mixer_slider_unpack_volume (s, v, volumes); + + if (track->num_channels > 1) { + GST_LOG_OBJECT (s, "volume: left=%d, right=%d", volumes[0], volumes[1]); + } else { + GST_LOG_OBJECT (s, "volume: mono=%d", volumes[0]); + } + + return TRUE; +} + +gboolean +gst_oss4_mixer_slider_set_volume (GstOss4MixerSlider * s, const gint * volumes) +{ + GstMixerTrack *track = GST_MIXER_TRACK (s); + int val = 0; + + /* if we're supposed to be muted, and are 'simulating' the mute because + * we don't have a mute control, don't actually change the volume, just + * save it as the new desired volume for later when we get unmuted again */ + if (!GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_NO_MUTE)) { + if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE) && !s->mc->mute) + goto done; + } + + val = gst_oss4_mixer_slider_pack_volume (s, volumes); + + if (track->num_channels > 1) { + GST_LOG_OBJECT (s, "left=%d, right=%d", volumes[0], volumes[1]); + } else { + GST_LOG_OBJECT (s, "mono=%d", volumes[0]); + } + + if (!gst_oss4_mixer_set_control_val (s->mixer, s->mc, val)) + return FALSE; + +done: + + s->volumes[0] = volumes[0]; + if (track->num_channels == 2) + s->volumes[1] = volumes[1]; + + return TRUE; +} + +gboolean +gst_oss4_mixer_slider_set_record (GstOss4MixerSlider * s, gboolean record) +{ + /* There doesn't seem to be a way to do this using the OSS4 mixer API, so + * just do nothing here for now. */ + return FALSE; +} + +gboolean +gst_oss4_mixer_slider_set_mute (GstOss4MixerSlider * s, gboolean mute) +{ + GstMixerTrack *track = GST_MIXER_TRACK (s); + gboolean ret; + + /* if the control does not support muting, then do not do anything */ + if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_NO_MUTE)) { + return TRUE; + } + + /* If we do not have a mute control, simulate mute (which is a bit broken, + * since we can not differentiate between capture/playback volume etc., so + * we just assume that setting the volume to 0 would be the same as muting + * this control) */ + if (s->mc->mute == NULL) { + int volume; + + if (mute) { + /* make sure the current volume values get saved. */ + gst_oss4_mixer_slider_get_volume (s, s->volumes); + volume = 0; + } else { + volume = gst_oss4_mixer_slider_pack_volume (s, s->volumes); + } + ret = gst_oss4_mixer_set_control_val (s->mixer, s->mc, volume); + } else { + ret = gst_oss4_mixer_set_control_val (s->mixer, s->mc->mute, ! !mute); + } + + if (mute) { + track->flags |= GST_MIXER_TRACK_MUTE; + } else { + track->flags &= ~GST_MIXER_TRACK_MUTE; + } + + return ret; +} + +GstMixerTrack * +gst_oss4_mixer_slider_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc) +{ + GstOss4MixerSlider *s; + GstMixerTrack *track; + gint volumes[2] = { 0, }; + + s = g_object_new (GST_TYPE_OSS4_MIXER_SLIDER, "untranslated-label", + mc->mixext.extname, NULL); + + track = GST_MIXER_TRACK (s); + + /* caller will set track->label and track->flags */ + + s->mc = mc; + s->mixer = mixer; + + /* we don't do value scaling but just present a scale of 0-maxvalue */ + track->min_volume = 0; + track->max_volume = mc->mixext.maxvalue; + + switch (mc->mixext.type) { + case MIXT_MONOSLIDER: + case MIXT_MONOSLIDER16: + case MIXT_SLIDER: + track->num_channels = 1; + break; + case MIXT_STEREOSLIDER: + case MIXT_STEREOSLIDER16: + track->num_channels = 2; + break; + default: + g_return_val_if_reached (NULL); + } + + GST_LOG_OBJECT (track, "min=%d, max=%d, channels=%d", track->min_volume, + track->max_volume, track->num_channels); + + if (!gst_oss4_mixer_slider_get_volume (s, volumes)) { + GST_WARNING_OBJECT (track, "failed to read volume, returning NULL"); + g_object_unref (track); + track = NULL; + } + + return track; +} + +/* This is called from the watch thread */ +void +gst_oss4_mixer_slider_process_change_unlocked (GstMixerTrack * track) +{ + GstOss4MixerSlider *s = GST_OSS4_MIXER_SLIDER_CAST (track); + + if (s->mc->mute != NULL && s->mc->mute->changed) { + gst_mixer_mute_toggled (GST_MIXER (s->mixer), track, + ! !s->mc->mute->last_val); + } else { + /* nothing to do here, since we don't/can't easily implement the record + * flag */ + } + + if (s->mc->changed) { + gint volumes[2] = { 0, 0 }; + + gst_oss4_mixer_slider_unpack_volume (s, s->mc->last_val, volumes); + + /* if we 'simulate' the mute, update flag when the volume changes */ + if (s->mc->mute == NULL) { + if (volumes[0] == 0 && volumes[1] == 0) { + track->flags |= GST_MIXER_TRACK_MUTE; + } else { + track->flags &= ~GST_MIXER_TRACK_MUTE; + } + } + + gst_mixer_volume_changed (GST_MIXER (s->mixer), track, volumes); + } +} diff --git a/sys/oss4/oss4-mixer-slider.h b/sys/oss4/oss4-mixer-slider.h new file mode 100644 index 0000000..3bee33f --- /dev/null +++ b/sys/oss4/oss4-mixer-slider.h @@ -0,0 +1,70 @@ +/* GStreamer OSS4 mixer slider control + * Copyright (C) 2007-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_OSS4_MIXER_SLIDER_H +#define GST_OSS4_MIXER_SLIDER_H + +#include <gst/gst.h> +#include <gst/interfaces/mixer.h> + +#include "oss4-mixer.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OSS4_MIXER_SLIDER (gst_oss4_mixer_slider_get_type()) +#define GST_OSS4_MIXER_SLIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_MIXER_SLIDER,GstOss4MixerSlider)) +#define GST_OSS4_MIXER_SLIDER_CAST(obj) ((GstOss4MixerSlider *)(obj)) +#define GST_OSS4_MIXER_SLIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_MIXER_SLIDER,GstOss4MixerSliderClass)) +#define GST_IS_OSS4_MIXER_SLIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_MIXER_SLIDER)) +#define GST_IS_OSS4_MIXER_SLIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_MIXER_SLIDER)) + +typedef struct _GstOss4MixerSlider GstOss4MixerSlider; +typedef struct _GstOss4MixerSliderClass GstOss4MixerSliderClass; + +struct _GstOss4MixerSlider { + GstMixerTrack mixer_track; + + GstOss4MixerControl * mc; + GstOss4Mixer * mixer; /* the mixer we belong to (no ref taken) */ + gint volumes[2]; /* left/mono, right */ +}; + +struct _GstOss4MixerSliderClass { + GstMixerTrackClass mixer_track_class; +}; + +GType gst_oss4_mixer_slider_get_type (void); + +GstMixerTrack * gst_oss4_mixer_slider_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc); + +gboolean gst_oss4_mixer_slider_get_volume (GstOss4MixerSlider * s, gint * volumes); + +gboolean gst_oss4_mixer_slider_set_volume (GstOss4MixerSlider * s, const gint * volumes); + +gboolean gst_oss4_mixer_slider_set_record (GstOss4MixerSlider * s, gboolean record); + +gboolean gst_oss4_mixer_slider_set_mute (GstOss4MixerSlider * s, gboolean mute); + +void gst_oss4_mixer_slider_process_change_unlocked (GstMixerTrack * track); + +G_END_DECLS + +#endif /* GST_OSS4_MIXER_SLIDER_H */ + + diff --git a/sys/oss4/oss4-mixer-switch.c b/sys/oss4/oss4-mixer-switch.c new file mode 100644 index 0000000..0a6ce5b --- /dev/null +++ b/sys/oss4/oss4-mixer-switch.c @@ -0,0 +1,150 @@ +/* GStreamer OSS4 mixer on/off switch control + * Copyright (C) 2007-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. + */ + +/* A simple ON/OFF 'switch' in gnome-volume-control / GstMixer is represented + * by a GstMixerTrack with no channels. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gst/gst-i18n-plugin.h> + +#define NO_LEGACY_MIXER +#include "oss4-mixer-switch.h" +#include "oss4-soundcard.h" + +GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug); +#define GST_CAT_DEFAULT oss4mixer_debug + +/* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */ +G_DEFINE_TYPE (GstOss4MixerSwitch, gst_oss4_mixer_switch, GST_TYPE_MIXER_TRACK); + +static void +gst_oss4_mixer_switch_class_init (GstOss4MixerSwitchClass * klass) +{ + /* nothing to do here */ +} + +static void +gst_oss4_mixer_switch_init (GstOss4MixerSwitch * s) +{ + /* nothing to do here */ +} + +gboolean +gst_oss4_mixer_switch_set (GstOss4MixerSwitch * s, gboolean disabled) +{ + GstMixerTrack *track; + int newval; + + track = GST_MIXER_TRACK (s); + + newval = disabled ? GST_MIXER_TRACK_MUTE : 0; + + if (newval == (track->flags & GST_MIXER_TRACK_MUTE)) { + GST_LOG_OBJECT (s, "switch is already %d, doing nothing", newval); + return TRUE; + } + + if (!gst_oss4_mixer_set_control_val (s->mixer, s->mc, !disabled)) { + GST_WARNING_OBJECT (s, "could not set switch to %d", !disabled); + return FALSE; + } + + if (disabled) { + track->flags |= GST_MIXER_TRACK_MUTE; + } else { + track->flags &= ~GST_MIXER_TRACK_MUTE; + } + + GST_LOG_OBJECT (s, "set switch to %d", newval); + + return TRUE; +} + +gboolean +gst_oss4_mixer_switch_get (GstOss4MixerSwitch * s, gboolean * disabled) +{ + GstMixerTrack *track; + int enabled = -1; + + track = GST_MIXER_TRACK (s); + + if (!gst_oss4_mixer_get_control_val (s->mixer, s->mc, &enabled) + || (enabled < 0)) { + GST_WARNING_OBJECT (s, "could not get switch state"); + return FALSE; + } + + if (enabled) { + track->flags &= ~GST_MIXER_TRACK_MUTE; + } else { + track->flags |= GST_MIXER_TRACK_MUTE; + } + *disabled = (enabled == 0); + + return TRUE; +} + +GstMixerTrack * +gst_oss4_mixer_switch_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc) +{ + GstOss4MixerSwitch *s; + GstMixerTrack *track; + int cur = -1; + + s = g_object_new (GST_TYPE_OSS4_MIXER_SWITCH, "untranslated-label", + mc->mixext.extname, NULL); + + s->mixer = mixer; + s->mc = mc; + + track = GST_MIXER_TRACK (s); + + /* caller will set track->label and track->flags */ + + track->num_channels = 0; + track->min_volume = 0; + track->max_volume = 0; + + if (!gst_oss4_mixer_get_control_val (s->mixer, s->mc, &cur) || cur < 0) + return NULL; + + if (cur) { + track->flags &= ~GST_MIXER_TRACK_MUTE; + } else { + track->flags |= GST_MIXER_TRACK_MUTE; + } + + return track; +} + +/* This is called from the watch thread */ +void +gst_oss4_mixer_switch_process_change_unlocked (GstMixerTrack * track) +{ + GstOss4MixerSwitch *s = GST_OSS4_MIXER_SWITCH_CAST (track); + + if (!s->mc->changed) + return; + + gst_mixer_mute_toggled (GST_MIXER (s->mixer), track, !s->mc->last_val); +} diff --git a/sys/oss4/oss4-mixer-switch.h b/sys/oss4/oss4-mixer-switch.h new file mode 100644 index 0000000..a8ab83f --- /dev/null +++ b/sys/oss4/oss4-mixer-switch.h @@ -0,0 +1,65 @@ +/* GStreamer OSS4 mixer on/off switch control + * Copyright (C) 2007-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_OSS4_MIXER_SWITCH_H +#define GST_OSS4_MIXER_SWITCH_H + +#include <gst/gst.h> +#include <gst/interfaces/mixer.h> + +#include "oss4-mixer.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OSS4_MIXER_SWITCH (gst_oss4_mixer_switch_get_type()) +#define GST_OSS4_MIXER_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_MIXER_SWITCH,GstOss4MixerSwitch)) +#define GST_OSS4_MIXER_SWITCH_CAST(obj) ((GstOss4MixerSwitch *)(obj)) +#define GST_OSS4_MIXER_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_MIXER_SWITCH,GstOss4MixerSwitchClass)) +#define GST_IS_OSS4_MIXER_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_MIXER_SWITCH)) +#define GST_IS_OSS4_MIXER_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_MIXER_SWITCH)) + +typedef struct _GstOss4MixerSwitch GstOss4MixerSwitch; +typedef struct _GstOss4MixerSwitchClass GstOss4MixerSwitchClass; + +struct _GstOss4MixerSwitch { + GstMixerTrack mixer_track; + + GstOss4MixerControl * mc; + GstOss4Mixer * mixer; /* the mixer we belong to (no ref taken) */ +}; + +struct _GstOss4MixerSwitchClass { + GstMixerTrackClass mixer_track_class; +}; + +GType gst_oss4_mixer_switch_get_type (void); + +gboolean gst_oss4_mixer_switch_set (GstOss4MixerSwitch * s, gboolean enabled); + +gboolean gst_oss4_mixer_switch_get (GstOss4MixerSwitch * s, gboolean * enabled); + +GstMixerTrack * gst_oss4_mixer_switch_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc); + +void gst_oss4_mixer_switch_process_change_unlocked (GstMixerTrack * track); + +G_END_DECLS + +#endif /* GST_OSS4_MIXER_SWITCH_H */ + + diff --git a/sys/oss4/oss4-mixer.c b/sys/oss4/oss4-mixer.c new file mode 100644 index 0000000..03e2d9d --- /dev/null +++ b/sys/oss4/oss4-mixer.c @@ -0,0 +1,1862 @@ +/* GStreamer OSS4 mixer implementation + * Copyright (C) 2007-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 mixer library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:element-oss4mixer + * + * This element lets you adjust sound input and output levels with the + * Open Sound System (OSS) version 4. 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> + * oss4mixer can't be used in a sensible way in gst-launch. + * </para> + * </refsect2> + * + * Since: 0.10.7 + */ + +/* Note: ioctl calls on the same open mixer device are serialised via + * the object lock to make sure we don't do concurrent ioctls from two + * different threads (e.g. app thread and mixer watch thread), since that + * will probably confuse OSS. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> + +#include <gst/interfaces/mixer.h> +#include <gst/gst-i18n-plugin.h> +#include "gst/glib-compat-private.h" + +#include <glib/gprintf.h> + +#define NO_LEGACY_MIXER + +#include "oss4-audio.h" +#include "oss4-mixer.h" +#include "oss4-mixer-enum.h" +#include "oss4-mixer-slider.h" +#include "oss4-mixer-switch.h" +#include "oss4-property-probe.h" +#include "oss4-soundcard.h" + +#define GST_OSS4_MIXER_WATCH_INTERVAL 500 /* in millisecs, ie. 0.5s */ + +GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug); +#define GST_CAT_DEFAULT oss4mixer_debug + +#define DEFAULT_DEVICE NULL +#define DEFAULT_DEVICE_NAME NULL + +enum +{ + PROP_0, + PROP_DEVICE, + PROP_DEVICE_NAME +}; + +static void gst_oss4_mixer_init_interfaces (GType type); + +GST_BOILERPLATE_FULL (GstOss4Mixer, gst_oss4_mixer, GstElement, + GST_TYPE_ELEMENT, gst_oss4_mixer_init_interfaces); + +static GstStateChangeReturn gst_oss4_mixer_change_state (GstElement * + element, GstStateChange transition); + +static void gst_oss4_mixer_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_oss4_mixer_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_oss4_mixer_finalize (GObject * object); + +static gboolean gst_oss4_mixer_open (GstOss4Mixer * mixer, + gboolean silent_errors); +static void gst_oss4_mixer_close (GstOss4Mixer * mixer); + +static gboolean gst_oss4_mixer_enum_control_update_enum_list (GstOss4Mixer * m, + GstOss4MixerControl * mc); + +#ifndef GST_DISABLE_GST_DEBUG +static const gchar *mixer_ext_type_get_name (gint type); +static const gchar *mixer_ext_flags_get_string (gint flags); +#endif + +static void +gst_oss4_mixer_base_init (gpointer klass) +{ + gst_element_class_set_details_simple (GST_ELEMENT_CLASS (klass), + "OSS v4 Audio Mixer", "Generic/Audio", + "Control sound input and output levels with OSS4", + "Tim-Philipp Müller <tim centricular net>"); +} + +static void +gst_oss4_mixer_class_init (GstOss4MixerClass * klass) +{ + GstElementClass *element_class; + GObjectClass *gobject_class; + + element_class = (GstElementClass *) klass; + gobject_class = (GObjectClass *) klass; + + gobject_class->finalize = gst_oss4_mixer_finalize; + gobject_class->set_property = gst_oss4_mixer_set_property; + gobject_class->get_property = gst_oss4_mixer_get_property; + + /** + * GstOss4Mixer:device + * + * OSS4 mixer device (e.g. /dev/oss/hdaudio0/mix0 or /dev/mixerN) + * + **/ + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", + "OSS mixer device (e.g. /dev/oss/hdaudio0/mix0 or /dev/mixerN) " + "(NULL = use first mixer device found)", DEFAULT_DEVICE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstOss4Mixer:device-name + * + * Human-readable name of the sound device. May be NULL if the device is + * not open (ie. when the mixer is in NULL state) + * + **/ + 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)); + + element_class->change_state = GST_DEBUG_FUNCPTR (gst_oss4_mixer_change_state); +} + +static void +gst_oss4_mixer_finalize (GObject * obj) +{ + GstOss4Mixer *mixer = GST_OSS4_MIXER (obj); + + g_free (mixer->device); + + G_OBJECT_CLASS (parent_class)->finalize (obj); +} + +static void +gst_oss4_mixer_reset (GstOss4Mixer * mixer) +{ + mixer->fd = -1; + mixer->need_update = TRUE; + memset (&mixer->last_mixext, 0, sizeof (oss_mixext)); +} + +static void +gst_oss4_mixer_init (GstOss4Mixer * mixer, GstOss4MixerClass * g_class) +{ + mixer->device = g_strdup (DEFAULT_DEVICE); + mixer->device_name = NULL; + + gst_oss4_mixer_reset (mixer); +} + +static void +gst_oss4_mixer_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOss4Mixer *mixer = GST_OSS4_MIXER (object); + + switch (prop_id) { + case PROP_DEVICE: + GST_OBJECT_LOCK (mixer); + if (!GST_OSS4_MIXER_IS_OPEN (mixer)) { + g_free (mixer->device); + mixer->device = g_value_dup_string (value); + /* unset any cached device-name */ + g_free (mixer->device_name); + mixer->device_name = NULL; + } else { + g_warning ("%s: can't change \"device\" property while mixer is open", + GST_OBJECT_NAME (mixer)); + } + GST_OBJECT_UNLOCK (mixer); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_oss4_mixer_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstOss4Mixer *mixer = GST_OSS4_MIXER (object); + + switch (prop_id) { + case PROP_DEVICE: + GST_OBJECT_LOCK (mixer); + g_value_set_string (value, mixer->device); + GST_OBJECT_UNLOCK (mixer); + break; + case PROP_DEVICE_NAME: + GST_OBJECT_LOCK (mixer); + /* If device is set, try to retrieve the name even if we're not open */ + if (mixer->fd == -1 && mixer->device != NULL) { + if (gst_oss4_mixer_open (mixer, TRUE)) { + g_value_set_string (value, mixer->device_name); + gst_oss4_mixer_close (mixer); + } else { + g_value_set_string (value, mixer->device_name); + } + } else { + g_value_set_string (value, mixer->device_name); + } + GST_OBJECT_UNLOCK (mixer); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_oss4_mixer_open (GstOss4Mixer * mixer, gboolean silent_errors) +{ + struct oss_mixerinfo mi = { 0, }; + gchar *device; + + g_return_val_if_fail (!GST_OSS4_MIXER_IS_OPEN (mixer), FALSE); + + if (mixer->device) + device = g_strdup (mixer->device); + else + device = gst_oss4_audio_find_device (GST_OBJECT_CAST (mixer)); + + /* desperate times, desperate measures */ + if (device == NULL) + device = g_strdup ("/dev/mixer"); + + GST_INFO_OBJECT (mixer, "Trying to open OSS4 mixer device '%s'", device); + + mixer->fd = open (device, O_RDWR, 0); + if (mixer->fd < 0) + goto open_failed; + + /* Make sure it's OSS4. If it's old OSS, let the old ossmixer handle it */ + if (!gst_oss4_audio_check_version (GST_OBJECT (mixer), mixer->fd)) + goto legacy_oss; + + GST_INFO_OBJECT (mixer, "Opened mixer device '%s', which is mixer %d", + device, mi.dev); + + /* Get device name for currently open fd */ + mi.dev = -1; + if (ioctl (mixer->fd, SNDCTL_MIXERINFO, &mi) == 0) { + mixer->modify_counter = mi.modify_counter; + if (mi.name[0] != '\0') { + mixer->device_name = g_strdup (mi.name); + } + } else { + mixer->modify_counter = 0; + } + + if (mixer->device_name == NULL) { + mixer->device_name = g_strdup ("Unknown"); + } + GST_INFO_OBJECT (mixer, "device name = '%s'", mixer->device_name); + + mixer->open_device = device; + + return TRUE; + + /* ERRORS */ +open_failed: + { + if (!silent_errors) { + GST_ELEMENT_ERROR (mixer, RESOURCE, OPEN_READ_WRITE, + (_("Could not open audio device for mixer control handling.")), + GST_ERROR_SYSTEM); + } else { + GST_DEBUG_OBJECT (mixer, "open failed: %s (ignoring errors)", + g_strerror (errno)); + } + g_free (device); + return FALSE; + } +legacy_oss: + { + gst_oss4_mixer_close (mixer); + if (!silent_errors) { + GST_ELEMENT_ERROR (mixer, RESOURCE, OPEN_READ_WRITE, + (_("Could not open audio device for mixer control handling. " + "This version of the Open Sound System is not supported by this " + "element.")), ("Try the 'ossmixer' element instead")); + } else { + GST_DEBUG_OBJECT (mixer, "open failed: legacy oss (ignoring errors)"); + } + g_free (device); + return FALSE; + } +} + +static void +gst_oss4_mixer_control_free (GstOss4MixerControl * mc) +{ + g_list_free (mc->children); + g_list_free (mc->mute_group); + g_free (mc->enum_vals); + memset (mc, 0, sizeof (GstOss4MixerControl)); + g_free (mc); +} + +static void +gst_oss4_mixer_free_tracks (GstOss4Mixer * mixer) +{ + g_list_foreach (mixer->tracks, (GFunc) g_object_unref, NULL); + g_list_free (mixer->tracks); + mixer->tracks = NULL; + + g_list_foreach (mixer->controls, (GFunc) gst_oss4_mixer_control_free, NULL); + g_list_free (mixer->controls); + mixer->controls = NULL; +} + +static void +gst_oss4_mixer_close (GstOss4Mixer * mixer) +{ + g_free (mixer->device_name); + mixer->device_name = NULL; + + g_free (mixer->open_device); + mixer->open_device = NULL; + + gst_oss4_mixer_free_tracks (mixer); + + if (mixer->fd != -1) { + close (mixer->fd); + mixer->fd = -1; + } + + gst_oss4_mixer_reset (mixer); +} + +static void +gst_oss4_mixer_watch_process_changes (GstOss4Mixer * mixer) +{ + GList *c, *t, *tracks = NULL; + + GST_INFO_OBJECT (mixer, "mixer interface or control changed"); + + /* this is all with the mixer object lock held */ + + /* we go through the list backwards so we can bail out faster when the entire + * interface needs to be rebuilt */ + for (c = g_list_last (mixer->controls); c != NULL; c = c->prev) { + GstOss4MixerControl *mc = c->data; + oss_mixer_value ossval = { 0, }; + + mc->changed = FALSE; + mc->list_changed = FALSE; + + /* not interested in controls we don't expose in the mixer interface */ + if (!mc->used) + continue; + + /* don't try to read a value from controls that don't have one */ + if (mc->mixext.type == MIXT_DEVROOT || mc->mixext.type == MIXT_GROUP) + continue; + + /* is this an enum control whose list may change? */ + if (mc->mixext.type == MIXT_ENUM && mc->enum_version != 0) { + if (gst_oss4_mixer_enum_control_update_enum_list (mixer, mc)) + mc->list_changed = TRUE; + } + + ossval.dev = mc->mixext.dev; + ossval.ctrl = mc->mixext.ctrl; + ossval.timestamp = mc->mixext.timestamp; + + if (ioctl (mixer->fd, SNDCTL_MIX_READ, &ossval) == -1) { + if (errno == EIDRM || errno == EFAULT) { + GST_DEBUG ("%s has disappeared", mc->mixext.extname); + goto mixer_changed; + } + GST_WARNING_OBJECT (mixer, "MIX_READ failed: %s", g_strerror (errno)); + /* just ignore, move on to next one */ + continue; + } + + if (ossval.value == mc->last_val) { /* no change */ + /* GST_LOG_OBJECT (mixer, "%s hasn't changed", mc->mixext.extname); */ + continue; + } + + mc->last_val = ossval.value; + GST_LOG_OBJECT (mixer, "%s changed value to %u 0x%08x", + mc->mixext.extname, ossval.value, ossval.value); + mc->changed = TRUE; + } + + /* copy list and take track refs, so we can safely drop the object lock, + * which we need to do to be able to post messages on the bus */ + tracks = g_list_copy (mixer->tracks); + g_list_foreach (tracks, (GFunc) g_object_ref, NULL); + + GST_OBJECT_UNLOCK (mixer); + + /* since we don't know (or want to know exactly) which controls belong to + * which track, we just go through the tracks one-by-one now and make them + * check themselves if any of their controls have changed and which messages + * to post on the bus as a result */ + for (t = tracks; t != NULL; t = t->next) { + GstMixerTrack *track = t->data; + + if (GST_IS_OSS4_MIXER_SLIDER (track)) { + gst_oss4_mixer_slider_process_change_unlocked (track); + } else if (GST_IS_OSS4_MIXER_SWITCH (track)) { + gst_oss4_mixer_switch_process_change_unlocked (track); + } else if (GST_IS_OSS4_MIXER_ENUM (track)) { + gst_oss4_mixer_enum_process_change_unlocked (track); + } + + g_object_unref (track); + } + g_list_free (tracks); + + GST_OBJECT_LOCK (mixer); + return; + +mixer_changed: + { + GST_OBJECT_UNLOCK (mixer); + gst_mixer_mixer_changed (GST_MIXER (mixer)); + GST_OBJECT_LOCK (mixer); + return; + } +} + +/* This thread watches the mixer for changes in a somewhat inefficient way + * (running an ioctl every half second or so). This is still better and + * cheaper than apps polling all tracks for changes a few times a second + * though. Needs more thought. There's probably (hopefully) a way to get + * notifications via the fd directly somehow. */ +static gpointer +gst_oss4_mixer_watch_thread (gpointer thread_data) +{ + GstOss4Mixer *mixer = GST_OSS4_MIXER_CAST (thread_data); + + GST_DEBUG_OBJECT (mixer, "watch thread running"); + + GST_OBJECT_LOCK (mixer); + while (!mixer->watch_shutdown) { + oss_mixerinfo mi = { 0, }; + GTimeVal tv; + + mi.dev = -1; + if (ioctl (mixer->fd, SNDCTL_MIXERINFO, &mi) == 0) { + if (mixer->modify_counter != mi.modify_counter) { + /* GST_LOG ("processing changes"); */ + gst_oss4_mixer_watch_process_changes (mixer); + mixer->modify_counter = mi.modify_counter; + } else { + /* GST_LOG ("no changes"); */ + } + } else { + GST_WARNING_OBJECT (mixer, "MIXERINFO failed: %s", g_strerror (errno)); + } + + /* we could move the _get_current_time out of the loop and just do the + * add in ever iteration, which would be less exact, but who cares */ + g_get_current_time (&tv); + g_time_val_add (&tv, GST_OSS4_MIXER_WATCH_INTERVAL * 1000); + (void) g_cond_timed_wait (mixer->watch_cond, GST_OBJECT_GET_LOCK (mixer), + &tv); + } + GST_OBJECT_UNLOCK (mixer); + + GST_DEBUG_OBJECT (mixer, "watch thread done"); + gst_object_unref (mixer); + return NULL; +} + +/* call with object lock held */ +static void +gst_oss4_mixer_wake_up_watch_task (GstOss4Mixer * mixer) +{ + GST_LOG_OBJECT (mixer, "signalling watch thread to wake up"); + g_cond_signal (mixer->watch_cond); +} + +static void +gst_oss4_mixer_stop_watch_task (GstOss4Mixer * mixer) +{ + if (mixer->watch_thread) { + GST_OBJECT_LOCK (mixer); + mixer->watch_shutdown = TRUE; + GST_LOG_OBJECT (mixer, "signalling watch thread to stop"); + g_cond_signal (mixer->watch_cond); + GST_OBJECT_UNLOCK (mixer); + GST_LOG_OBJECT (mixer, "waiting for watch thread to join"); + g_thread_join (mixer->watch_thread); + GST_DEBUG_OBJECT (mixer, "watch thread stopped"); + mixer->watch_thread = NULL; + } + + if (mixer->watch_cond) { + g_cond_free (mixer->watch_cond); + mixer->watch_cond = NULL; + } +} + +static void +gst_oss4_mixer_start_watch_task (GstOss4Mixer * mixer) +{ + GError *err = NULL; + + mixer->watch_cond = g_cond_new (); + mixer->watch_shutdown = FALSE; + +#if !GLIB_CHECK_VERSION (2, 31, 0) + mixer->watch_thread = g_thread_create (gst_oss4_mixer_watch_thread, + gst_object_ref (mixer), TRUE, &err); +#else + mixer->watch_thread = g_thread_try_new ("oss4-mixer-thread", + gst_oss4_mixer_watch_thread, gst_object_ref (mixer), &err); +#endif + + if (mixer->watch_thread == NULL) { + GST_ERROR_OBJECT (mixer, "Could not create watch thread: %s", err->message); + g_cond_free (mixer->watch_cond); + mixer->watch_cond = NULL; + g_error_free (err); + } +} + +static GstStateChangeReturn +gst_oss4_mixer_change_state (GstElement * element, GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstOss4Mixer *mixer = GST_OSS4_MIXER (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!gst_oss4_mixer_open (mixer, FALSE)) + return GST_STATE_CHANGE_FAILURE; + gst_oss4_mixer_start_watch_task (mixer); + 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_READY_TO_NULL: + gst_oss4_mixer_stop_watch_task (mixer); + gst_oss4_mixer_close (mixer); + break; + default: + break; + } + + return ret; +} + +/* === GstMixer interface === */ + +static inline gboolean +gst_oss4_mixer_contains_track (GstMixer * mixer, GstMixerTrack * track) +{ + return (g_list_find (GST_OSS4_MIXER (mixer)->tracks, track) != NULL); +} + +static inline gboolean +gst_oss4_mixer_contains_options (GstMixer * mixer, GstMixerOptions * options) +{ + return (g_list_find (GST_OSS4_MIXER (mixer)->tracks, options) != NULL); +} + +static void +gst_oss4_mixer_post_mixer_changed_msg (GstOss4Mixer * mixer) +{ + /* only post mixer-changed message once */ + if (!mixer->need_update) { + gst_mixer_mixer_changed (GST_MIXER (mixer)); + mixer->need_update = TRUE; + } +} + +/* call with mixer object lock held to serialise ioctl */ +gboolean +gst_oss4_mixer_get_control_val (GstOss4Mixer * mixer, GstOss4MixerControl * mc, + int *val) +{ + oss_mixer_value ossval = { 0, }; + + if (GST_OBJECT_TRYLOCK (mixer)) { + GST_ERROR ("must be called with mixer lock held"); + GST_OBJECT_UNLOCK (mixer); + } + + ossval.dev = mc->mixext.dev; + ossval.ctrl = mc->mixext.ctrl; + ossval.timestamp = mc->mixext.timestamp; + + if (ioctl (mixer->fd, SNDCTL_MIX_READ, &ossval) == -1) { + if (errno == EIDRM) { + GST_DEBUG_OBJECT (mixer, "MIX_READ failed: mixer interface has changed"); + gst_oss4_mixer_post_mixer_changed_msg (mixer); + } else { + GST_WARNING_OBJECT (mixer, "MIX_READ failed: %s", g_strerror (errno)); + } + *val = 0; + mc->last_val = 0; + return FALSE; + } + + *val = ossval.value; + mc->last_val = ossval.value; + GST_LOG_OBJECT (mixer, "got value 0x%08x from %s)", *val, mc->mixext.extname); + return TRUE; +} + +/* call with mixer object lock held to serialise ioctl */ +gboolean +gst_oss4_mixer_set_control_val (GstOss4Mixer * mixer, GstOss4MixerControl * mc, + int val) +{ + oss_mixer_value ossval = { 0, }; + + ossval.dev = mc->mixext.dev; + ossval.ctrl = mc->mixext.ctrl; + ossval.timestamp = mc->mixext.timestamp; + ossval.value = val; + + if (GST_OBJECT_TRYLOCK (mixer)) { + GST_ERROR ("must be called with mixer lock held"); + GST_OBJECT_UNLOCK (mixer); + } + + if (ioctl (mixer->fd, SNDCTL_MIX_WRITE, &ossval) == -1) { + if (errno == EIDRM) { + GST_LOG_OBJECT (mixer, "MIX_WRITE failed: mixer interface has changed"); + gst_oss4_mixer_post_mixer_changed_msg (mixer); + } else { + GST_WARNING_OBJECT (mixer, "MIX_WRITE failed: %s", g_strerror (errno)); + } + return FALSE; + } + + mc->last_val = val; + GST_LOG_OBJECT (mixer, "set value 0x%08x on %s", val, mc->mixext.extname); + return TRUE; +} + +#if 0 +static gchar * +gst_oss4_mixer_control_get_pretty_name (GstOss4MixerControl * mc) +{ + gchar *name; + + const gchar *name, *u; + + /* "The id field is the original name given by the driver when it called + * mixer_ext_create_control. This name can be used by fully featured GUI + * mixers. However this name should be downshifted and cut before the last + * underscore ("_") to get the proper name. For example mixer control name + * created as "MYDRV_MAINVOL" will become just "mainvol" after this + * transformation." */ + name = mc->mixext.extname; + u = MAX (strrchr (name, '_'), strrchr (name, '.')); + if (u != NULL) + name = u + 1; + + /* maybe capitalize the first letter? */ + return g_ascii_strdown (name, -1); + /* the .id thing doesn't really seem to work right, ie. for some sliders + * it's just '-' so you have to use the name of the parent control etc. + * let's not use it for now, much too painful. */ + if (g_str_has_prefix (mc->mixext.extname, "misc.")) + name = g_strdup (mc->mixext.extname + 5); + else + name = g_strdup (mc->mixext.extname); + /* chop off trailing digit (only one for now) */ + if (strlen (name) > 0 && g_ascii_isdigit (name[strlen (name) - 1])) + name[strlen (name) - 1] = '\0'; + g_strdelimit (name, ".", ' '); + return name; +} +#endif + +/* these translations are a bit ad-hoc and horribly incomplete; it is not + * really going to work this way with all the different chipsets and drivers. + * We also use these for translating option values. */ +static struct +{ + const gchar oss_name[32]; + const gchar *label; +} labels[] = { + { + "volume", N_("Volume")}, { + "master", N_("Master")}, { + "front", N_("Front")}, { + "rear", N_("Rear")}, { + "headphones", N_("Headphones")}, { + "center", N_("Center")}, { + "lfe", N_("LFE")}, { + "surround", N_("Surround")}, { + "side", N_("Side")}, { + "speaker", N_("Built-in Speaker")}, { + "aux1-out", N_("AUX 1 Out")}, { + "aux2-out", N_("AUX 2 Out")}, { + "aux-out", N_("AUX Out")}, { + "bass", N_("Bass")}, { + "treble", N_("Treble")}, { + "3d-depth", N_("3D Depth")}, { + "3d-center", N_("3D Center")}, { + "3d-enhance", N_("3D Enhance")}, { + "phone", N_("Telephone")}, { + "mic", N_("Microphone")}, { + "line-out", N_("Line Out")}, { + "line-in", N_("Line In")}, { + "linein", N_("Line In")}, { + "cd", N_("Internal CD")}, { + "video", N_("Video In")}, { + "aux1-in", N_("AUX 1 In")}, { + "aux2-in", N_("AUX 2 In")}, { + "aux-in", N_("AUX In")}, { + "pcm", N_("PCM")}, { + "record-gain", N_("Record Gain")}, { + "igain", N_("Record Gain")}, { + "ogain", N_("Output Gain")}, { + "micboost", N_("Microphone Boost")}, { + "loopback", N_("Loopback")}, { + "diag", N_("Diagnostic")}, { + "loudness", N_("Bass Boost")}, { + "outputs", N_("Playback Ports")}, { + "input", N_("Input")}, { + "inputs", N_("Record Source")}, { + "record-source", N_("Record Source")}, { + "monitor-source", N_("Monitor Source")}, { + "beep", N_("Keyboard Beep")}, { + "monitor-gain", N_("Monitor")}, { + "stereo-simulate", N_("Simulate Stereo")}, { + "stereo", N_("Stereo")}, { + "multich", N_("Surround Sound")}, { + "mic-gain", N_("Microphone Gain")}, { + "speaker-source", N_("Speaker Source")}, { + "mic-source", N_("Microphone Source")}, { + "jack", N_("Jack")}, { + "center/lfe", N_("Center / LFE")}, { + "stereo-mix", N_("Stereo Mix")}, { + "mono-mix", N_("Mono Mix")}, { + "input-mix", N_("Input Mix")}, { + "spdif-in", N_("SPDIF In")}, { + "spdif-out", N_("SPDIF Out")}, { + "mic1", N_("Microphone 1")}, { + "mic2", N_("Microphone 2")}, { + "digital-out", N_("Digital Out")}, { + "digital-in", N_("Digital In")}, { + "hdmi", N_("HDMI")}, { + "modem", N_("Modem")}, { + "handset", N_("Handset")}, { + "other", N_("Other")}, { + "stereo", N_("Stereo")}, { + "none", N_("None")}, { + "on", N_("On")}, { + "off", N_("Off")}, { + "mute", N_("Mute")}, { + "fast", N_("Fast")}, { + /* TRANSLATORS: "Very Low" is a quality setting here */ + "very-low", N_("Very Low")}, { + /* TRANSLATORS: "Low" is a quality setting here */ + "low", N_("Low")}, { + /* TRANSLATORS: "Medium" is a quality setting here */ + "medium", N_("Medium")}, { + /* TRANSLATORS: "High" is a quality setting here */ + "high", N_("High")}, { + /* TRANSLATORS: "Very High" is a quality setting here */ + "very-high", N_("Very High")}, { + "high+", N_("Very High")}, { + /* TRANSLATORS: "Production" is a quality setting here */ + "production", N_("Production")}, { + "fp-mic", N_("Front Panel Microphone")}, { + "fp-linein", N_("Front Panel Line In")}, { + "fp-headphones", N_("Front Panel Headphones")}, { + "fp-lineout", N_("Front Panel Line Out")}, { + "green", N_("Green Connector")}, { + "pink", N_("Pink Connector")}, { + "blue", N_("Blue Connector")}, { + "white", N_("White Connector")}, { + "black", N_("Black Connector")}, { + "gray", N_("Gray Connector")}, { + "orange", N_("Orange Connector")}, { + "red", N_("Red Connector")}, { + "yellow", N_("Yellow Connector")}, { + "fp-green", N_("Green Front Panel Connector")}, { + "fp-pink", N_("Pink Front Panel Connector")}, { + "fp-blue", N_("Blue Front Panel Connector")}, { + "fp-white", N_("White Front Panel Connector")}, { + "fp-black", N_("Black Front Panel Connector")}, { + "fp-gray", N_("Gray Front Panel Connector")}, { + "fp-orange", N_("Orange Front Panel Connector")}, { + "fp-red", N_("Red Front Panel Connector")}, { + "fp-yellow", N_("Yellow Front Panel Connector")}, { + "spread", N_("Spread Output")}, { + "downmix", N_("Downmix")}, + /* FIXME translate Audigy NX USB labels) */ +/* + { "rec.src", N_("Record Source") }, + { "output.mute", N_("Mute output") } + headph (Controller group) + headph.src (Enumeration control) + headph.mute (On/Off switch) + digital2 (Controller group) + digital2.src (Enumeration control) + digital2.mute (On/Off switch) + digital (Controller group) + digital.mute1 (On/Off switch) + digital.vol (Controller group) + digital.vol.front (Stereo slider (0-255)) + digital.vol.surr (Stereo slider (0-255)) + digital.vol.c/l (Stereo slider (0-255)) + digital.vol.center (Stereo slider (0-255)) + digital.mute2 (On/Off switch) + digital.vol (Stereo slider (0-255)) + line (Controller group) + line.mute (On/Off switch) + line.vol (Stereo slider (0-255)) + play-altset (Enumeration control) + rec-altset (Enumeration control) +*/ +}; + +/* Decent i18n is pretty much impossible with OSS's way of providing us with + * mixer labels (and the fact that they are pretty much random), but that + * doesn't mean we shouldn't at least try. */ +static gchar * +gst_oss4_mixer_control_get_translated_name (GstOss4MixerControl * mc) +{ + gchar name[128] = { 0, }; + gchar vmix_str[32] = { '\0', }; + gchar *ptr; + int dummy, i; + int num = -1; + gboolean function_suffix = FALSE; + + /* main virtual mixer controls (we hide the stream volumes) */ + if (sscanf (mc->mixext.extname, "vmix%d-%32c", &dummy, vmix_str) == 2) { + if (strcmp (vmix_str, "src") == 0) + return g_strdup (_("Virtual Mixer Input")); + else if (strcmp (vmix_str, "vol") == 0) + return g_strdup (_("Virtual Mixer Output")); + else if (strcmp (vmix_str, "channels") == 0) + return g_strdup (_("Virtual Mixer Channels")); + } + + g_strlcpy (name, mc->mixext.extname, sizeof (name)); + + /* we deal with either "connector." or "jack." */ + if ((g_str_has_prefix (name, "connector.")) || + (g_str_has_prefix (name, "jack."))) { + ptr = strchr (mc->mixext.extname, '.'); + ptr++; + g_strlcpy (name, ptr, sizeof (name)); + } + + /* special handling for jack retasking suffixes */ + if (g_str_has_suffix (name, ".function") || g_str_has_suffix (name, ".mode")) { + function_suffix = TRUE; + ptr = strrchr (name, '.'); + *ptr = 0; + } + + /* parse off trailing numbers */ + i = strlen (name); + while ((i > 0) && (g_ascii_isdigit (name[i - 1]))) { + i--; + } + /* the check catches the case where the control name is just a number */ + if ((i > 0) && (name[i] != '\0')) { + num = atoi (name + i); + name[i] = '\0'; + } + + /* look for a match, progressively skipping '.' delimited prefixes as we go */ + ptr = name; + do { + if (*ptr == '.') + ptr++; + for (i = 0; i < G_N_ELEMENTS (labels); ++i) { + if (g_ascii_strcasecmp (ptr, labels[i].oss_name) == 0) { + g_strlcpy (name, _(labels[i].label), sizeof (name)); + goto append_suffixes; + } + } + } while ((ptr = strchr (ptr, '.')) != NULL); + + /* failing that, just replace periods with spaces */ + g_strdelimit (name, ".", ' '); + +append_suffixes: + if (num > -1) { + if (function_suffix) { + /* TRANSLATORS: name + number of a volume mixer control */ + return g_strdup_printf (_("%s %d Function"), name, num); + } else { + return g_strdup_printf ("%s %d", name, num); + } + } else { + if (function_suffix) { + /* TRANSLATORS: name of a volume mixer control */ + return g_strdup_printf (_("%s Function"), name); + } else { + return g_strdup (name); + } + } +} + +static const gchar * +gst_oss4_mixer_control_get_translated_option (const gchar * name) +{ + int i; + for (i = 0; i < G_N_ELEMENTS (labels); ++i) { + if (g_ascii_strcasecmp (name, labels[i].oss_name) == 0) { + return _(labels[i].label); + } + } + return (name); +} + +#ifndef GST_DISABLE_GST_DEBUG +static const gchar * +mixer_ext_type_get_name (gint type) +{ + switch (type) { + case MIXT_DEVROOT: + return "Device root entry"; + case MIXT_GROUP: + return "Controller group"; + case MIXT_ONOFF: + return "On/Off switch"; + case MIXT_ENUM: + return "Enumeration control"; + case MIXT_MONOSLIDER: + return "Mono slider (0-255)"; + case MIXT_STEREOSLIDER: + return "Stereo slider (0-255)"; + case MIXT_MESSAGE: + return "Textual message"; /* whatever this is */ + case MIXT_MONOVU: + return "Mono VU meter value"; + case MIXT_STEREOVU: + return "Stereo VU meter value"; + case MIXT_MONOPEAK: + return "Mono VU meter peak value"; + case MIXT_STEREOPEAK: + return "Stereo VU meter peak value"; + case MIXT_RADIOGROUP: + return "Radio button group"; + case MIXT_MARKER: /* Separator between normal and extension entries */ + return "Separator"; + case MIXT_VALUE: + return "Decimal value entry"; + case MIXT_HEXVALUE: + return "Hex value entry"; + case MIXT_SLIDER: + return "Mono slider (31-bit value range)"; + case MIXT_3D: + return "3D"; /* what's this? */ + case MIXT_MONOSLIDER16: + return "Mono slider (0-32767)"; + case MIXT_STEREOSLIDER16: + return "Stereo slider (0-32767)"; + case MIXT_MUTE: + return "Mute switch"; + default: + break; + } + return "unknown"; +} +#endif /* GST_DISABLE_GST_DEBUG */ + +#ifndef GST_DISABLE_GST_DEBUG +static const gchar * +mixer_ext_flags_get_string (gint flags) +{ + struct + { + gint flag; + gchar nick[16]; + } all_flags[] = { + /* first the important ones */ + { + MIXF_MAINVOL, "MAINVOL"}, { + MIXF_PCMVOL, "PCMVOL"}, { + MIXF_RECVOL, "RECVOL"}, { + MIXF_MONVOL, "MONVOL"}, { + MIXF_DESCR, "DESCR"}, + /* now the rest in the right order */ + { + MIXF_READABLE, "READABLE"}, { + MIXF_WRITEABLE, "WRITABLE"}, { + MIXF_POLL, "POLL"}, { + MIXF_HZ, "HZ"}, { + MIXF_STRING, "STRING"}, { + MIXF_DYNAMIC, "DYNAMIC"}, { + MIXF_OKFAIL, "OKFAIL"}, { + MIXF_FLAT, "FLAT"}, { + MIXF_LEGACY, "LEGACY"}, { + MIXF_CENTIBEL, "CENTIBEL"}, { + MIXF_DECIBEL, "DECIBEL"}, { + MIXF_WIDE, "WIDE"} + }; + GString *s; + GQuark q; + gint i; + + if (flags == 0) + return "None"; + + s = g_string_new (""); + for (i = 0; i < G_N_ELEMENTS (all_flags); ++i) { + if ((flags & all_flags[i].flag)) { + if (s->len > 0) + g_string_append (s, " | "); + g_string_append (s, all_flags[i].nick); + flags &= ~all_flags[i].flag; /* unset */ + } + } + + /* unknown flags? */ + if (flags != 0) { + if (s->len > 0) + g_string_append (s, " | "); + g_string_append (s, "???"); + } + + /* we'll just put it into the global quark table (cheeky, eh?) */ + q = g_quark_from_string (s->str); + g_string_free (s, TRUE); + + return g_quark_to_string (q); +} +#endif /* GST_DISABLE_GST_DEBUG */ + +#ifndef GST_DISABLE_GST_DEBUG +static void +gst_oss4_mixer_control_dump_tree (GstOss4MixerControl * mc, gint depth) +{ + GList *c; + gchar spaces[64]; + gint i; + + depth = MIN (sizeof (spaces) - 1, depth); + for (i = 0; i < depth; ++i) + spaces[i] = ' '; + spaces[i] = '\0'; + + GST_LOG ("%s%s (%s)", spaces, mc->mixext.extname, + mixer_ext_type_get_name (mc->mixext.type)); + for (c = mc->children; c != NULL; c = c->next) { + GstOss4MixerControl *child_mc = (GstOss4MixerControl *) c->data; + + gst_oss4_mixer_control_dump_tree (child_mc, depth + 2); + } +} +#endif /* GST_DISABLE_GST_DEBUG */ + +static GList * +gst_oss4_mixer_get_controls (GstOss4Mixer * mixer) +{ + GstOss4MixerControl *root_mc = NULL; + oss_mixerinfo mi = { 0, }; + GList *controls = NULL; + GList *l; + guint i; + + /* Get info for currently open fd */ + mi.dev = -1; + if (ioctl (mixer->fd, SNDCTL_MIXERINFO, &mi) == -1) + goto no_mixerinfo; + + if (mi.nrext <= 0) { + GST_DEBUG ("mixer %s has no controls", mi.id); + return NULL; + } + + GST_INFO ("Reading controls for mixer %s", mi.id); + + for (i = 0; i < mi.nrext; ++i) { + GstOss4MixerControl *mc; + oss_mixext mix_ext = { 0, }; + + mix_ext.dev = mi.dev; + mix_ext.ctrl = i; + + if (ioctl (mixer->fd, SNDCTL_MIX_EXTINFO, &mix_ext) == -1) { + GST_DEBUG ("SNDCTL_MIX_EXTINFO failed on mixer %s, control %d: %s", + mi.id, i, g_strerror (errno)); + continue; + } + + /* if this is the last one, save it for is-interface-up-to-date checking */ + if (i == mi.nrext) + mixer->last_mixext = mix_ext; + + mc = g_new0 (GstOss4MixerControl, 1); + mc->mixext = mix_ext; + + /* both control_no and desc fields are pretty useless, ie. not always set, + * if ever, so not listed here */ + GST_INFO ("Control %d", mix_ext.ctrl); + GST_INFO (" name : %s", mix_ext.extname); + GST_INFO (" type : %s (%d)", mixer_ext_type_get_name (mix_ext.type), + mix_ext.type); + GST_INFO (" flags : %s (0x%04x)", + mixer_ext_flags_get_string (mix_ext.flags), mix_ext.flags); + GST_INFO (" parent : %d", mix_ext.parent); + + if (!MIXEXT_IS_ROOT (mix_ext)) { + /* find parent (we assume it comes in the list before the child) */ + for (l = controls; l != NULL; l = l->next) { + GstOss4MixerControl *parent_mc = (GstOss4MixerControl *) l->data; + + if (parent_mc->mixext.ctrl == mix_ext.parent) { + mc->parent = parent_mc; + parent_mc->children = g_list_append (parent_mc->children, mc); + break; + } + } + if (mc->parent == NULL) { + GST_ERROR_OBJECT (mixer, "couldn't find parent for control %d", i); + g_free (mc); + continue; + } + } else if (root_mc == NULL) { + root_mc = mc; + } else { + GST_WARNING_OBJECT (mixer, "two root controls?!"); + } + + controls = g_list_prepend (controls, mc); + } + +#ifndef GST_DISABLE_GST_DEBUG + gst_oss4_mixer_control_dump_tree (root_mc, 0); +#endif + + return g_list_reverse (controls); + +/* ERRORS */ +no_mixerinfo: + { + GST_WARNING ("SNDCTL_MIXERINFO failed on mixer device %s: %s", mi.id, + g_strerror (errno)); + return NULL; + } +} + +static void +gst_oss4_mixer_controls_guess_master (GstOss4Mixer * mixer, + const GList * controls) +{ + GstOss4MixerControl *master_mc = NULL; + const GList *l; + + for (l = controls; l != NULL; l = l->next) { + GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data; + + /* do we need to check if it's a slider type here? */ + if ((mc->mixext.flags & MIXF_PCMVOL)) { + GST_INFO_OBJECT (mixer, "First PCM control: %s", mc->mixext.extname); + master_mc = mc; + break; + } + + if (((mc->mixext.flags & MIXF_MAINVOL)) && master_mc == NULL) { + GST_INFO_OBJECT (mixer, "First main volume control: %s", + mc->mixext.extname); + master_mc = mc; + } + } + + if (master_mc != NULL) + master_mc->is_master = TRUE; +} + +/* type: -1 for all types, otherwise just return siblings with requested type */ +static GList * +gst_oss4_mixer_control_get_siblings (GstOss4MixerControl * mc, gint type) +{ + GList *s, *siblings = NULL; + + if (mc->parent == NULL) + return NULL; + + for (s = mc->parent->children; s != NULL; s = s->next) { + GstOss4MixerControl *sibling = (GstOss4MixerControl *) s->data; + + if (mc != sibling && (type < 0 || sibling->mixext.type == type)) + siblings = g_list_append (siblings, sibling); + } + + return siblings; +} + +static void +gst_oss4_mixer_controls_find_sliders (GstOss4Mixer * mixer, + const GList * controls) +{ + const GList *l; + + for (l = controls; l != NULL; l = l->next) { + GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data; + GList *s, *siblings; + + if (!MIXEXT_IS_SLIDER (mc->mixext) || mc->parent == NULL || mc->used) + continue; + + mc->is_slider = TRUE; + mc->used = TRUE; + + siblings = gst_oss4_mixer_control_get_siblings (mc, -1); + + /* Note: the names can be misleading and may not reflect the actual + * hierarchy of the controls, e.g. it's possible that a slider is called + * connector.green and the mute control then connector.green.mute, but + * both controls are in fact siblings and both children of the group + * 'green' instead of mute being a child of connector.green as the naming + * would seem to suggest */ + GST_LOG ("Slider: %s, parent=%s, %d siblings", mc->mixext.extname, + mc->parent->mixext.extname, g_list_length (siblings)); + + for (s = siblings; s != NULL; s = s->next) { + GstOss4MixerControl *sibling = (GstOss4MixerControl *) s->data; + + GST_LOG (" %s (%s)", sibling->mixext.extname, + mixer_ext_type_get_name (sibling->mixext.type)); + + if (sibling->mixext.type == MIXT_MUTE || + g_str_has_suffix (sibling->mixext.extname, ".mute")) { + /* simple case: slider with single mute sibling. We assume the .mute + * suffix in the name won't change - can't really do much else anyway */ + if (sibling->mixext.type == MIXT_ONOFF || + sibling->mixext.type == MIXT_MUTE) { + GST_LOG (" mute control for %s is %s", mc->mixext.extname, + sibling->mixext.extname); + mc->mute = sibling; + sibling->used = TRUE; + } + /* a group of .mute controls. We assume they are all switches here */ + if (sibling->mixext.type == MIXT_GROUP) { + GList *m; + + for (m = sibling->children; m != NULL; m = m->next) { + GstOss4MixerControl *grouped_sibling = m->data; + + if (grouped_sibling->mixext.type == MIXT_ONOFF || + grouped_sibling->mixext.type == MIXT_MUTE) { + GST_LOG (" %s is grouped mute control for %s", + grouped_sibling->mixext.extname, mc->mixext.extname); + mc->mute_group = g_list_append (mc->mute_group, grouped_sibling); + } + } + + GST_LOG (" %s has a group of %d mute controls", + mc->mixext.extname, g_list_length (mc->mute_group)); + + /* we don't mark the individual mute controls as used, only the + * group control, as we still want individual switches for the + * individual controls */ + sibling->used = TRUE; + } + } + } + g_list_free (siblings); + } +} + +/* should be called with the mixer object lock held because of the ioctl; + * returns TRUE if the list was read the first time or modified */ +static gboolean +gst_oss4_mixer_enum_control_update_enum_list (GstOss4Mixer * mixer, + GstOss4MixerControl * mc) +{ + oss_mixer_enuminfo ei = { 0, }; + guint num_existing = 0; + int i; + + /* count and existing values */ + while (mc->enum_vals != NULL && mc->enum_vals[num_existing] != 0) + ++num_existing; + + ei.dev = mc->mixext.dev; + ei.ctrl = mc->mixext.ctrl; + + /* if we have create a generic list with numeric IDs already and the + * number of values hasn't changed, then there's not much to do here */ + if (mc->no_list && mc->enum_vals != NULL && + num_existing == mc->mixext.maxvalue) { + return FALSE; + } + + /* if we have a list and it doesn't change, there's nothing to do either */ + if (mc->enum_vals != NULL && mc->enum_version == 0) + return FALSE; + + if (ioctl (mixer->fd, SNDCTL_MIX_ENUMINFO, &ei) == -1) { + g_free (mc->enum_vals); + mc->enum_vals = g_new0 (GQuark, mc->mixext.maxvalue + 1); + + GST_DEBUG ("no enum info available, creating numeric values from 0-%d", + mc->mixext.maxvalue - 1); + + /* "It is possible that some enum controls don't have any name list + * available. In this case the application should automatically generate + * list of numbers (0 to N-1)" */ + for (i = 0; i < mc->mixext.maxvalue; ++i) { + gchar num_str[8]; + + g_snprintf (num_str, sizeof (num_str), "%d", i); + mc->enum_vals[i] = g_quark_from_string (num_str); + } + mc->enum_version = 0; /* the only way to change is via maxvalue */ + } else { + /* old list same as current list? */ + if (mc->enum_vals != NULL && mc->enum_version == ei.version) + return FALSE; + + /* no list yet, or the list has changed */ + GST_LOG ("%s", (mc->enum_vals) ? "enum list has changed" : "reading list"); + if (ei.nvalues != mc->mixext.maxvalue) { + GST_WARNING_OBJECT (mixer, "Enum: %s, nvalues %d != maxvalue %d", + mc->mixext.extname, ei.nvalues, mc->mixext.maxvalue); + mc->mixext.maxvalue = MIN (ei.nvalues, mc->mixext.maxvalue); + } + + mc->mixext.maxvalue = MIN (mc->mixext.maxvalue, OSS_ENUM_MAXVALUE); + + g_free (mc->enum_vals); + mc->enum_vals = g_new0 (GQuark, mc->mixext.maxvalue + 1); + for (i = 0; i < mc->mixext.maxvalue; ++i) { + GST_LOG (" %s", ei.strings + ei.strindex[i]); + mc->enum_vals[i] = + g_quark_from_string (gst_oss4_mixer_control_get_translated_option + (ei.strings + ei.strindex[i])); + } + } + + return TRUE; +} + +static void +gst_oss4_mixer_controls_find_enums (GstOss4Mixer * mixer, + const GList * controls) +{ + const GList *l; + + for (l = controls; l != NULL; l = l->next) { + GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data; + + if (mc->mixext.type != MIXT_ENUM || mc->used) + continue; + + mc->is_enum = TRUE; + mc->used = TRUE; + + /* Note: enums are special: for most controls, the maxvalue is inclusive, + * but for enum controls it's actually exclusive (boggle), so that + * mixext.maxvalue = num_values */ + + GST_LOG ("Enum: %s, parent=%s, num_enums=%d", mc->mixext.extname, + mc->parent->mixext.extname, mc->mixext.maxvalue); + + gst_oss4_mixer_enum_control_update_enum_list (mixer, mc); + } +} + +static void +gst_oss4_mixer_controls_find_switches (GstOss4Mixer * mixer, + const GList * controls) +{ + const GList *l; + + for (l = controls; l != NULL; l = l->next) { + GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data; + + if (mc->used) + continue; + + if (mc->mixext.type != MIXT_ONOFF && mc->mixext.type != MIXT_MUTE) + continue; + + mc->is_switch = TRUE; + mc->used = TRUE; + + GST_LOG ("Switch: %s, parent=%s", mc->mixext.extname, + mc->parent->mixext.extname); + } +} + +static void +gst_oss4_mixer_controls_find_virtual (GstOss4Mixer * mixer, + const GList * controls) +{ + const GList *l; + + for (l = controls; l != NULL; l = l->next) { + GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data; + + /* or sscanf (mc->mixext.extname, "vmix%d-out.", &n) == 1 ? */ + /* for now we just flag all virtual controls with managed labels, those + * are really more appropriate for a pavucontrol-type control thing than + * the (more hardware-oriented) mixer interface */ + if (mc->mixext.id[0] == '@') { + mc->is_virtual = TRUE; + GST_LOG ("%s is virtual control with managed label", mc->mixext.extname); + } + } +} + +static void +gst_oss4_mixer_controls_dump_unused (GstOss4Mixer * mixer, + const GList * controls) +{ + const GList *l; + + for (l = controls; l != NULL; l = l->next) { + GstOss4MixerControl *mc = (GstOss4MixerControl *) l->data; + + if (mc->used) + continue; + + switch (mc->mixext.type) { + case MIXT_DEVROOT: + case MIXT_GROUP: + case MIXT_MESSAGE: + case MIXT_MONOVU: + case MIXT_STEREOVU: + case MIXT_MONOPEAK: + case MIXT_STEREOPEAK: + case MIXT_MARKER: + continue; /* not interested in these types of controls */ + case MIXT_MONODB: + case MIXT_STEREODB: + GST_DEBUG ("obsolete control type %d", mc->mixext.type); + continue; + case MIXT_MONOSLIDER: + case MIXT_STEREOSLIDER: + case MIXT_SLIDER: + case MIXT_MONOSLIDER16: + case MIXT_STEREOSLIDER16: + /* this shouldn't happen */ + GST_ERROR ("unused slider control?!"); + continue; + case MIXT_VALUE: + case MIXT_HEXVALUE: + /* value entry, not sure what to do with that, skip for now */ + continue; + case MIXT_ONOFF: + case MIXT_MUTE: + case MIXT_ENUM: + case MIXT_3D: + case MIXT_RADIOGROUP: + GST_DEBUG ("FIXME: handle %s %s", + mixer_ext_type_get_name (mc->mixext.type), mc->mixext.extname); + break; + default: + GST_WARNING ("unknown control type %d", mc->mixext.type); + continue; + } + } +} + +static GList * +gst_oss4_mixer_create_tracks (GstOss4Mixer * mixer, const GList * controls) +{ + const GList *c; + GList *tracks = NULL; + + for (c = controls; c != NULL; c = c->next) { + GstOss4MixerControl *mc = (GstOss4MixerControl *) c->data; + GstMixerTrack *track = NULL; + + if (mc->is_virtual) + continue; + + if (mc->is_slider) { + track = gst_oss4_mixer_slider_new (mixer, mc); + } else if (mc->is_enum) { + track = gst_oss4_mixer_enum_new (mixer, mc); + } else if (mc->is_switch) { + track = gst_oss4_mixer_switch_new (mixer, mc); + } + + if (track == NULL) + continue; + + track->label = gst_oss4_mixer_control_get_translated_name (mc); + track->flags = 0; + + GST_LOG ("translated label: %s [%s] = %s", track->label, mc->mixext.id, + track->label); + + /* This whole 'a track is either INPUT or OUTPUT' model is just flawed, + * esp. if a slider's role can be changed on the fly, like when you change + * function of a connector. What should we do in that case? Change the flag + * and make the app rebuild the interface? Ignore it? */ + if (mc->mixext.flags & (MIXF_MAINVOL | MIXF_PCMVOL)) { + track->flags = GST_MIXER_TRACK_OUTPUT | GST_MIXER_TRACK_WHITELIST; + + } else if (mc->mixext.flags & MIXF_RECVOL) { + /* record gain whitelisted by default */ + track->flags = GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD | + GST_MIXER_TRACK_WHITELIST; + + } else if (mc->mixext.flags & MIXF_MONVOL) { + /* monitor sources not whitelisted by default */ + track->flags = GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD; + } + + /* + * The kernel may give us better clues about the scope of a control. + * If so, try to honor it. + */ + switch (mc->mixext.desc & MIXEXT_SCOPE_MASK) { + case MIXEXT_SCOPE_INPUT: + case MIXEXT_SCOPE_RECSWITCH: + track->flags |= GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD | + GST_MIXER_TRACK_WHITELIST; + break; + case MIXEXT_SCOPE_MONITOR: + /* don't whitelist monitor tracks by default */ + track->flags |= GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD; + break; + case MIXEXT_SCOPE_OUTPUT: + track->flags = GST_MIXER_TRACK_OUTPUT | GST_MIXER_TRACK_WHITELIST; + break; + } + + if (mc->is_master) { + track->flags |= GST_MIXER_TRACK_OUTPUT; + } + + if (mc->is_master) + track->flags |= GST_MIXER_TRACK_MASTER; + + tracks = g_list_append (tracks, track); + } + + return tracks; +} + +static void +gst_oss4_mixer_update_tracks (GstOss4Mixer * mixer) +{ + GList *controls, *tracks; + + /* read and process controls */ + controls = gst_oss4_mixer_get_controls (mixer); + + gst_oss4_mixer_controls_guess_master (mixer, controls); + + gst_oss4_mixer_controls_find_sliders (mixer, controls); + + gst_oss4_mixer_controls_find_enums (mixer, controls); + + gst_oss4_mixer_controls_find_switches (mixer, controls); + + gst_oss4_mixer_controls_find_virtual (mixer, controls); + + gst_oss4_mixer_controls_dump_unused (mixer, controls); + + tracks = gst_oss4_mixer_create_tracks (mixer, controls); + + /* free old tracks and controls */ + gst_oss4_mixer_free_tracks (mixer); + + /* replace old with new */ + mixer->tracks = tracks; + mixer->controls = controls; +} + +static const GList * +gst_oss4_mixer_list_tracks (GstMixer * mixer_iface) +{ + GstOss4Mixer *mixer = GST_OSS4_MIXER (mixer_iface); + + g_return_val_if_fail (mixer != NULL, NULL); + g_return_val_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer), NULL); + + GST_OBJECT_LOCK (mixer); + + /* Do a read on the last control to check if the interface has changed */ + if (!mixer->need_update && mixer->last_mixext.ctrl > 0) { + GstOss4MixerControl mc = { {0,} + , + }; + int val; + + mc.mixext = mixer->last_mixext; + gst_oss4_mixer_get_control_val (mixer, &mc, &val); + } + + if (mixer->need_update || mixer->tracks == NULL) { + gst_oss4_mixer_update_tracks (mixer); + mixer->need_update = FALSE; + } + + GST_OBJECT_UNLOCK (mixer); + + return (const GList *) mixer->tracks; +} + +static void +gst_oss4_mixer_set_volume (GstMixer * mixer, GstMixerTrack * track, + gint * volumes) +{ + GstOss4Mixer *oss; + + g_return_if_fail (mixer != NULL); + g_return_if_fail (GST_IS_OSS4_MIXER (mixer)); + g_return_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer)); + g_return_if_fail (gst_oss4_mixer_contains_track (mixer, track)); + g_return_if_fail (volumes != NULL); + + oss = GST_OSS4_MIXER (mixer); + + GST_OBJECT_LOCK (oss); + + if (GST_IS_OSS4_MIXER_SLIDER (track)) { + gst_oss4_mixer_slider_set_volume (GST_OSS4_MIXER_SLIDER (track), volumes); + } + + GST_OBJECT_UNLOCK (oss); +} + +static void +gst_oss4_mixer_get_volume (GstMixer * mixer, GstMixerTrack * track, + gint * volumes) +{ + GstOss4Mixer *oss; + + g_return_if_fail (mixer != NULL); + g_return_if_fail (GST_IS_OSS4_MIXER (mixer)); + g_return_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer)); + g_return_if_fail (gst_oss4_mixer_contains_track (mixer, track)); + g_return_if_fail (volumes != NULL); + + oss = GST_OSS4_MIXER (mixer); + + GST_OBJECT_LOCK (oss); + + memset (volumes, 0, track->num_channels * sizeof (gint)); + + if (GST_IS_OSS4_MIXER_SWITCH (track)) { + gboolean enabled = FALSE; + gst_oss4_mixer_switch_get (GST_OSS4_MIXER_SWITCH (track), &enabled); + } + if (GST_IS_OSS4_MIXER_SLIDER (track)) { + gst_oss4_mixer_slider_get_volume (GST_OSS4_MIXER_SLIDER (track), volumes); + } + + GST_OBJECT_UNLOCK (oss); +} + +static void +gst_oss4_mixer_set_record (GstMixer * mixer, GstMixerTrack * track, + gboolean record) +{ + GstOss4Mixer *oss; + + g_return_if_fail (mixer != NULL); + g_return_if_fail (GST_IS_OSS4_MIXER (mixer)); + g_return_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer)); + g_return_if_fail (gst_oss4_mixer_contains_track (mixer, track)); + + oss = GST_OSS4_MIXER (mixer); + + GST_OBJECT_LOCK (oss); + + if (GST_IS_OSS4_MIXER_SLIDER (track)) { + gst_oss4_mixer_slider_set_record (GST_OSS4_MIXER_SLIDER (track), record); + } else if (GST_IS_OSS4_MIXER_SWITCH (track)) { + if ((track->flags & GST_MIXER_TRACK_INPUT)) { + gst_oss4_mixer_switch_set (GST_OSS4_MIXER_SWITCH (track), record); + } else { + GST_WARNING_OBJECT (track, "set_record called on non-INPUT track"); + } + } + + GST_OBJECT_UNLOCK (oss); +} + +static void +gst_oss4_mixer_set_mute (GstMixer * mixer, GstMixerTrack * track, gboolean mute) +{ + GstOss4Mixer *oss; + + g_return_if_fail (mixer != NULL); + g_return_if_fail (GST_IS_OSS4_MIXER (mixer)); + g_return_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer)); + g_return_if_fail (gst_oss4_mixer_contains_track (mixer, track)); + + oss = GST_OSS4_MIXER (mixer); + + GST_OBJECT_LOCK (oss); + + if (GST_IS_OSS4_MIXER_SLIDER (track)) { + gst_oss4_mixer_slider_set_mute (GST_OSS4_MIXER_SLIDER (track), mute); + } else if (GST_IS_OSS4_MIXER_SWITCH (track)) { + gst_oss4_mixer_switch_set (GST_OSS4_MIXER_SWITCH (track), mute); + } + + GST_OBJECT_UNLOCK (oss); +} + +static void +gst_oss4_mixer_set_option (GstMixer * mixer, GstMixerOptions * options, + gchar * value) +{ + GstOss4Mixer *oss; + + g_return_if_fail (mixer != NULL); + g_return_if_fail (value != NULL); + g_return_if_fail (GST_IS_OSS4_MIXER (mixer)); + g_return_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer)); + g_return_if_fail (GST_IS_OSS4_MIXER_ENUM (options)); + g_return_if_fail (gst_oss4_mixer_contains_options (mixer, options)); + + oss = GST_OSS4_MIXER (mixer); + + GST_OBJECT_LOCK (oss); + + if (!gst_oss4_mixer_enum_set_option (GST_OSS4_MIXER_ENUM (options), value)) { + /* not much we can do here but wake up the watch thread early, so it + * can do its thing and post messages if anything has changed */ + gst_oss4_mixer_wake_up_watch_task (oss); + } + + GST_OBJECT_UNLOCK (oss); +} + +static const gchar * +gst_oss4_mixer_get_option (GstMixer * mixer, GstMixerOptions * options) +{ + GstOss4Mixer *oss; + const gchar *current_val; + + g_return_val_if_fail (mixer != NULL, NULL); + g_return_val_if_fail (GST_IS_OSS4_MIXER (mixer), NULL); + g_return_val_if_fail (GST_OSS4_MIXER_IS_OPEN (mixer), NULL); + g_return_val_if_fail (GST_IS_OSS4_MIXER_ENUM (options), NULL); + g_return_val_if_fail (gst_oss4_mixer_contains_options (mixer, options), NULL); + + oss = GST_OSS4_MIXER (mixer); + + GST_OBJECT_LOCK (oss); + + current_val = gst_oss4_mixer_enum_get_option (GST_OSS4_MIXER_ENUM (options)); + + if (current_val == NULL) { + /* not much we can do here but wake up the watch thread early, so it + * can do its thing and post messages if anything has changed */ + gst_oss4_mixer_wake_up_watch_task (oss); + } + + GST_OBJECT_UNLOCK (oss); + + return current_val; +} + +static GstMixerFlags +gst_oss4_mixer_get_mixer_flags (GstMixer * mixer) +{ + return GST_MIXER_FLAG_AUTO_NOTIFICATIONS | GST_MIXER_FLAG_HAS_WHITELIST | + GST_MIXER_FLAG_GROUPING; +} + +static void +gst_oss4_mixer_interface_init (GstMixerClass * klass) +{ + GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; + + klass->list_tracks = gst_oss4_mixer_list_tracks; + klass->set_volume = gst_oss4_mixer_set_volume; + klass->get_volume = gst_oss4_mixer_get_volume; + klass->set_mute = gst_oss4_mixer_set_mute; + klass->set_record = gst_oss4_mixer_set_record; + klass->set_option = gst_oss4_mixer_set_option; + klass->get_option = gst_oss4_mixer_get_option; + klass->get_mixer_flags = gst_oss4_mixer_get_mixer_flags; +} + +/* Implement the horror that is GstImplementsInterface */ + +static gboolean +gst_oss4_mixer_supported (GstImplementsInterface * iface, GType iface_type) +{ + GstOss4Mixer *mixer; + + g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE); + + mixer = GST_OSS4_MIXER (iface); + + return GST_OSS4_MIXER_IS_OPEN (mixer); +} + +static void +gst_oss4_mixer_implements_interface_init (GstImplementsInterfaceClass * klass) +{ + klass->supported = gst_oss4_mixer_supported; +} + +static void +gst_oss4_mixer_init_interfaces (GType type) +{ + static const GInterfaceInfo implements_iface_info = { + (GInterfaceInitFunc) gst_oss4_mixer_implements_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo mixer_iface_info = { + (GInterfaceInitFunc) gst_oss4_mixer_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); + + gst_oss4_add_property_probe_interface (type); +} diff --git a/sys/oss4/oss4-mixer.h b/sys/oss4/oss4-mixer.h new file mode 100644 index 0000000..4eaff50 --- /dev/null +++ b/sys/oss4/oss4-mixer.h @@ -0,0 +1,128 @@ +/* GStreamer OSS4 mixer implementation + * Copyright (C) 2007-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 OSS4_MIXER_H +#define OSS4_MIXER_H + +#include <gst/gst.h> + +#include "oss4-soundcard.h" + +#define GST_OSS4_MIXER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_MIXER,GstOss4Mixer)) +#define GST_OSS4_MIXER_CAST(obj) ((GstOss4Mixer *)(obj)) +#define GST_OSS4_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_MIXER,GstOss4MixerClass)) +#define GST_IS_OSS4_MIXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_MIXER)) +#define GST_IS_OSS4_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_MIXER)) +#define GST_TYPE_OSS4_MIXER (gst_oss4_mixer_get_type()) + +#define GST_OSS4_MIXER_IS_OPEN(obj) (GST_OSS4_MIXER(obj)->fd != -1) + +typedef struct _GstOss4Mixer GstOss4Mixer; +typedef struct _GstOss4MixerClass GstOss4MixerClass; + +struct _GstOss4Mixer { + GstElement element; + + /*< private >*/ + + /* element bits'n'bops */ + gchar * device; + + /* mixer details */ + gint fd; /* file descriptor if open, or -1 */ + gchar * device_name; /* device description, or NULL */ + gchar * open_device; /* the device we opened */ + + GList * tracks; /* list of available tracks */ + GList * controls; /* list of available controls */ + gboolean need_update; /* re-read list of available tracks? */ + + oss_mixext last_mixext; /* we keep this around so we can + * easily check if the mixer + * interface has changed */ + + GThread * watch_thread; /* thread watching for value changes */ + GCond * watch_cond; + gint watch_shutdown; + gint modify_counter; /* from MIXERINFO */ + + /* for property probe interface */ + GList * property_probe_list; +}; + +struct _GstOss4MixerClass { + GstElementClass element_class; +}; + +/* helper struct holding info about one control */ +typedef struct _GstOss4MixerControl GstOss4MixerControl; + +struct _GstOss4MixerControl { + oss_mixext mixext; + GstOss4MixerControl *parent; /* NULL if root */ + GstOss4MixerControl *mute; /* sibling with mute function, or NULL */ + GList *mute_group; /* group of mute controls, or NULL */ + GList *children; /* GstOss4MixerControls (no ownership) */ + + GQuark *enum_vals; /* 0-terminated array of values or NULL */ + int enum_version; /* 0 = list won't change */ + + int last_val; /* last value seen */ + + gboolean is_virtual : 1; /* is a vmix control with dynamic label */ + gboolean is_master : 1; + gboolean is_slider : 1; /* represent as slider */ + gboolean is_switch : 1; /* represent as switch */ + gboolean is_enum : 1; /* represent as combo/enumeration */ + gboolean no_list : 1; /* enumeration with no list available */ + gboolean is_input : 1; /* is an input-related control */ + gboolean is_output : 1; /* is an output-related control */ + gboolean used : 1; /* whether we know what to do with this */ + + gboolean changed : 1; /* transient flag used by watch thread */ + gboolean list_changed : 1; /* transient flag used by watch thread */ +}; + +/* header says parent=-1 means root, but it can also be parent=ctrl */ +#define MIXEXT_IS_ROOT(me) ((me).parent == -1 || (me).parent == (me).ctrl) + +#define MIXEXT_IS_SLIDER(me) ((me).type == MIXT_MONOSLIDER || \ + (me).type == MIXT_STEREOSLIDER || (me).type == MIXT_MONOSLIDER16 || \ + (me).type == MIXT_STEREOSLIDER16 || (me).type == MIXT_SLIDER) + +#define MIXEXT_HAS_DESCRIPTION(me) (((me).flags & MIXF_DESCR) != 0) + +#define MIXEXT_ENUM_IS_AVAILABLE(me,num) \ + (((me).enum_present[num/8]) & (1 << (num % 8))) + + +GType gst_oss4_mixer_get_type (void); + +gboolean gst_oss4_mixer_get_control_val (GstOss4Mixer * mixer, + GstOss4MixerControl * mc, + int * val); + +gboolean gst_oss4_mixer_set_control_val (GstOss4Mixer * mixer, + GstOss4MixerControl * mc, + int val); + +G_END_DECLS + +#endif /* OSS4_MIXER_H */ + diff --git a/sys/oss4/oss4-property-probe.c b/sys/oss4/oss4-property-probe.c new file mode 100644 index 0000000..a99410e --- /dev/null +++ b/sys/oss4/oss4-property-probe.c @@ -0,0 +1,412 @@ +/* GStreamer OSS4 audio property probe interface implementation + * Copyright (C) 2007-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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gst/gst.h> + +#define NO_LEGACY_MIXER +#include "oss4-audio.h" +#include "oss4-mixer.h" +#include "oss4-sink.h" +#include "oss4-source.h" +#include "oss4-soundcard.h" +#include "oss4-property-probe.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +GST_DEBUG_CATEGORY_EXTERN (oss4_debug); +#define GST_CAT_DEFAULT oss4_debug + +static const GList * +gst_oss4_property_probe_get_properties (GstPropertyProbe * probe) +{ + GObjectClass *klass = G_OBJECT_GET_CLASS (probe); + GList *list; + + GST_OBJECT_LOCK (GST_OBJECT (probe)); + + /* we create a new list and store it in the instance struct, since apparently + * we forgot to update the API for 0.10 (and why don't we mark probable + * properties with a flag instead anyway?). A bit hackish, but what can you + * do (can't really use a static variable since the pspec will be different + * for src and sink class); this isn't particularly pretty, but the best + * we can do given that we can't create a common base class (we could do + * fancy things with the interface, or use g_object_set_data instead, but + * it's not really going to make it much better) */ + if (GST_IS_AUDIO_SINK_CLASS (klass)) { + list = GST_OSS4_SINK (probe)->property_probe_list; + } else if (GST_IS_AUDIO_SRC_CLASS (klass)) { + list = GST_OSS4_SOURCE (probe)->property_probe_list; + } else if (GST_IS_OSS4_MIXER_CLASS (klass)) { + list = GST_OSS4_MIXER (probe)->property_probe_list; + } else { + GST_OBJECT_UNLOCK (GST_OBJECT (probe)); + g_return_val_if_reached (NULL); + } + + if (list == NULL) { + GParamSpec *pspec; + + pspec = g_object_class_find_property (klass, "device"); + list = g_list_prepend (NULL, pspec); + + if (GST_IS_AUDIO_SINK_CLASS (klass)) { + GST_OSS4_SINK (probe)->property_probe_list = list; + } else if (GST_IS_AUDIO_SRC_CLASS (klass)) { + GST_OSS4_SOURCE (probe)->property_probe_list = list; + } else if (GST_IS_OSS4_MIXER_CLASS (klass)) { + GST_OSS4_MIXER (probe)->property_probe_list = list; + } + } + + GST_OBJECT_UNLOCK (GST_OBJECT (probe)); + + return list; +} + +static void +gst_oss4_property_probe_probe_property (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + if (!g_str_equal (pspec->name, "device")) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + } +} + +static gboolean +gst_oss4_property_probe_needs_probe (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + /* don't cache probed data */ + return TRUE; +} + +static gint +oss4_mixerinfo_priority_cmp (struct oss_mixerinfo *mi1, + struct oss_mixerinfo *mi2) +{ + /* return negative vaue if mi1 comes before mi2 */ + if (mi1->priority != mi2->priority) + return mi2->priority - mi1->priority; + + return strcmp (mi1->devnode, mi2->devnode); +} + +/* caller must ensure LOCK is taken (e.g. if ioctls need to be serialised) */ +gboolean +gst_oss4_property_probe_find_device_name (GstObject * obj, int fd, + const gchar * device_handle, gchar ** device_name) +{ + struct oss_sysinfo si = { {0,}, }; + gchar *name = NULL; + + if (ioctl (fd, SNDCTL_SYSINFO, &si) == 0) { + int i; + + for (i = 0; i < si.numaudios; ++i) { + struct oss_audioinfo ai = { 0, }; + + ai.dev = i; + if (ioctl (fd, SNDCTL_AUDIOINFO, &ai) == -1) { + GST_DEBUG_OBJECT (obj, "AUDIOINFO ioctl for device %d failed", i); + continue; + } + if (strcmp (ai.devnode, device_handle) == 0) { + name = g_strdup (ai.name); + break; + } + } + } else { + GST_WARNING_OBJECT (obj, "SYSINFO ioctl failed: %s", g_strerror (errno)); + } + + /* try ENGINEINFO as fallback (which is better than nothing) */ + if (name == NULL) { + struct oss_audioinfo ai = { 0, }; + + GST_LOG_OBJECT (obj, "device %s not listed in AUDIOINFO", device_handle); + ai.dev = -1; + if (ioctl (fd, SNDCTL_ENGINEINFO, &ai) == 0) + name = g_strdup (ai.name); + } + + GST_DEBUG_OBJECT (obj, "Device name: %s", GST_STR_NULL (name)); + + if (name != NULL) + *device_name = name; + + return (name != NULL); +} + +gboolean +gst_oss4_property_probe_find_device_name_nofd (GstObject * obj, + const gchar * device_handle, gchar ** device_name) +{ + gboolean res; + int fd; + + fd = open ("/dev/mixer", O_RDONLY); + if (fd < 0) + return FALSE; + + res = gst_oss4_property_probe_find_device_name (obj, fd, device_handle, + device_name); + + close (fd); + return res; +} + +static GList * +gst_oss4_property_probe_get_mixer_devices (GstObject * obj, int fd, + struct oss_sysinfo *si) +{ + GList *m, *mixers = NULL; + GList *devices = NULL; + + int i; + + GST_LOG_OBJECT (obj, "%d mixer devices", si->nummixers); + + /* first, find suitable mixer devices and sort by priority */ + for (i = 0; i < si->nummixers; ++i) { + struct oss_mixerinfo mi = { 0, }; + + mi.dev = i; + if (ioctl (fd, SNDCTL_MIXERINFO, &mi) == -1) { + GST_DEBUG_OBJECT (obj, "MIXERINFO ioctl for device %d failed", i); + continue; + } + + GST_INFO_OBJECT (obj, "mixer device %d:", i); + GST_INFO_OBJECT (obj, " enabled : %s", (mi.enabled) ? "yes" : + "no (powered off or unplugged)"); + GST_INFO_OBJECT (obj, " priority : %d", mi.priority); + GST_INFO_OBJECT (obj, " devnode : %s", mi.devnode); + GST_INFO_OBJECT (obj, " handle : %s", mi.handle); + GST_INFO_OBJECT (obj, " caps : 0x%02x", mi.caps); + GST_INFO_OBJECT (obj, " name : %s", mi.name); + + if (!mi.enabled) { + GST_DEBUG_OBJECT (obj, "mixer device is not usable/enabled, skipping"); + continue; + } + + /* only want mixers that control hardware directly */ + if ((mi.caps & MIXER_CAP_VIRTUAL)) { + GST_DEBUG_OBJECT (obj, "mixer device is a virtual device, skipping"); + continue; + } + + mixers = g_list_insert_sorted (mixers, g_memdup (&mi, sizeof (mi)), + (GCompareFunc) oss4_mixerinfo_priority_cmp); + } + + /* then create device list according to priority */ + for (m = mixers; m != NULL; m = m->next) { + struct oss_mixerinfo *mi = (struct oss_mixerinfo *) m->data; + + GST_LOG_OBJECT (obj, "mixer device: '%s'", mi->devnode); + devices = g_list_prepend (devices, g_strdup (mi->devnode)); + g_free (m->data); + } + g_list_free (mixers); + mixers = NULL; + + return g_list_reverse (devices); +} + +static GList * +gst_oss4_property_probe_get_audio_devices (GstObject * obj, int fd, + struct oss_sysinfo *si, int cap_mask) +{ + GList *devices = NULL; + int i; + + GST_LOG_OBJECT (obj, "%d audio/dsp devices", si->numaudios); + + for (i = 0; i < si->numaudios; ++i) { + struct oss_audioinfo ai = { 0, }; + + ai.dev = i; + if (ioctl (fd, SNDCTL_AUDIOINFO, &ai) == -1) { + GST_DEBUG_OBJECT (obj, "AUDIOINFO ioctl for device %d failed", i); + continue; + } + + if ((ai.caps & cap_mask) == 0) { + GST_DEBUG_OBJECT (obj, "audio device %d is not an %s device", i, + (cap_mask == PCM_CAP_OUTPUT) ? "output" : "input"); + continue; + } + + if (!ai.enabled) { + GST_DEBUG_OBJECT (obj, "audio device %d is not usable/enabled", i); + continue; + } + + GST_DEBUG_OBJECT (obj, "audio device %d looks ok: %s (\"%s\")", i, + ai.devnode, ai.name); + + devices = g_list_prepend (devices, g_strdup (ai.devnode)); + } + + return g_list_reverse (devices); +} + +static GValueArray * +gst_oss4_property_probe_get_values (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + struct oss_sysinfo si = { {0,}, }; + GValueArray *array = NULL; + GstObject *obj; + GList *devices, *l; + int cap_mask, fd = -1; + + if (!g_str_equal (pspec->name, "device")) { + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + return NULL; + } + + obj = GST_OBJECT (probe); + + GST_OBJECT_LOCK (obj); + + /* figure out whether the element is a source or sink */ + if (GST_IS_OSS4_SINK (probe)) { + GST_DEBUG_OBJECT (probe, "probing available output devices"); + cap_mask = PCM_CAP_OUTPUT; + fd = GST_OSS4_SINK (probe)->fd; + } else if (GST_IS_OSS4_SOURCE (probe)) { + GST_DEBUG_OBJECT (probe, "probing available input devices"); + cap_mask = PCM_CAP_INPUT; + fd = GST_OSS4_SOURCE (probe)->fd; + } else if (GST_IS_OSS4_MIXER (probe)) { + fd = GST_OSS4_MIXER (probe)->fd; + cap_mask = 0; + } else { + GST_OBJECT_UNLOCK (obj); + g_return_val_if_reached (NULL); + } + + /* copy fd if it's open, so we can just unconditionally close() later */ + if (fd != -1) + fd = dup (fd); + + /* this will also catch the unlikely case where the above dup() failed */ + if (fd == -1) { + fd = open ("/dev/mixer", O_RDONLY | O_NONBLOCK, 0); + if (fd < 0) + goto open_failed; + else if (!gst_oss4_audio_check_version (GST_OBJECT (probe), fd)) + goto legacy_oss; + } + + if (ioctl (fd, SNDCTL_SYSINFO, &si) == -1) + goto no_sysinfo; + + if (cap_mask != 0) { + devices = + gst_oss4_property_probe_get_audio_devices (obj, fd, &si, cap_mask); + } else { + devices = gst_oss4_property_probe_get_mixer_devices (obj, fd, &si); + } + + if (devices == NULL) { + GST_DEBUG_OBJECT (obj, "No devices found"); + goto done; + } + + array = g_value_array_new (1); + + for (l = devices; l != NULL; l = l->next) { + GValue val = { 0, }; + + g_value_init (&val, G_TYPE_STRING); + g_value_take_string (&val, (gchar *) l->data); + l->data = NULL; + g_value_array_append (array, &val); + g_value_unset (&val); + } + + GST_OBJECT_UNLOCK (obj); + + g_list_free (devices); + +done: + + close (fd); + + return array; + +/* ERRORS */ +open_failed: + { + GST_OBJECT_UNLOCK (GST_OBJECT (probe)); + GST_WARNING_OBJECT (probe, "Can't open file descriptor to probe " + "available devices: %s", g_strerror (errno)); + return NULL; + } +legacy_oss: + { + close (fd); + GST_OBJECT_UNLOCK (GST_OBJECT (probe)); + GST_DEBUG_OBJECT (probe, "Legacy OSS (ie. not OSSv4), not supported"); + return NULL; + } +no_sysinfo: + { + close (fd); + GST_OBJECT_UNLOCK (GST_OBJECT (probe)); + GST_WARNING_OBJECT (probe, "Can't open file descriptor to probe " + "available devices: %s", g_strerror (errno)); + return NULL; + } +} + +static void +gst_oss4_property_probe_interface_init (GstPropertyProbeInterface * iface) +{ + iface->get_properties = gst_oss4_property_probe_get_properties; + iface->probe_property = gst_oss4_property_probe_probe_property; + iface->needs_probe = gst_oss4_property_probe_needs_probe; + iface->get_values = gst_oss4_property_probe_get_values; +} + +void +gst_oss4_add_property_probe_interface (GType type) +{ + static const GInterfaceInfo probe_iface_info = { + (GInterfaceInitFunc) gst_oss4_property_probe_interface_init, + NULL, + NULL, + }; + + g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE, + &probe_iface_info); +} diff --git a/sys/oss4/oss4-property-probe.h b/sys/oss4/oss4-property-probe.h new file mode 100644 index 0000000..707af02 --- /dev/null +++ b/sys/oss4/oss4-property-probe.h @@ -0,0 +1,38 @@ +/* GStreamer OSS4 audio property probe interface implementation + * Copyright (C) 2007-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_OSS4_PROPERTY_PROBE_H +#define GST_OSS4_PROPERTY_PROBE_H + +#include <gst/interfaces/propertyprobe.h> + +void gst_oss4_add_property_probe_interface (GType type); + +gboolean gst_oss4_property_probe_find_device_name (GstObject * obj, + int fd, + const gchar * device_handle, + gchar ** device_name); + +gboolean gst_oss4_property_probe_find_device_name_nofd (GstObject * obj, + const gchar * device_handle, + gchar ** device_name); + +#endif /* GST_OSS4_PROPERTY_PROBE_H */ + + diff --git a/sys/oss4/oss4-sink.c b/sys/oss4/oss4-sink.c new file mode 100644 index 0000000..54e95b9 --- /dev/null +++ b/sys/oss4/oss4-sink.c @@ -0,0 +1,696 @@ +/* GStreamer OSS4 audio sink + * Copyright (C) 2007-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. + */ +/** + * SECTION:element-oss4sink + * + * This element lets you output sound using the Open Sound System (OSS) + * version 4. + * + * Note that you should almost always use generic audio conversion elements + * like audioconvert and audioresample in front of an audiosink to make sure + * your pipeline works under all circumstances (those conversion elements will + * act in passthrough-mode if no conversion is necessary). + * + * <refsect2> + * <title>Example pipelines</title> + * |[ + * gst-launch -v audiotestsrc ! audioconvert ! volume volume=0.1 ! oss4sink + * ]| will output a sine wave (continuous beep sound) to your sound card (with + * a very low volume as precaution). + * |[ + * gst-launch -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! oss4sink + * ]| will play an Ogg/Vorbis audio file and output it using the Open Sound System + * version 4. + * </refsect2> + * + * Since: 0.10.7 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> + +#include <gst/gst-i18n-plugin.h> +#include <gst/interfaces/streamvolume.h> + +#define NO_LEGACY_MIXER +#include "oss4-audio.h" +#include "oss4-sink.h" +#include "oss4-property-probe.h" +#include "oss4-soundcard.h" + +GST_DEBUG_CATEGORY_EXTERN (oss4sink_debug); +#define GST_CAT_DEFAULT oss4sink_debug + +static void gst_oss4_sink_init_interfaces (GType type); +static void gst_oss4_sink_dispose (GObject * object); +static void gst_oss4_sink_finalize (GObject * object); + +static void gst_oss4_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_oss4_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); + +static GstCaps *gst_oss4_sink_getcaps (GstBaseSink * bsink); +static gboolean gst_oss4_sink_open (GstAudioSink * asink, + gboolean silent_errors); +static gboolean gst_oss4_sink_open_func (GstAudioSink * asink); +static gboolean gst_oss4_sink_close (GstAudioSink * asink); +static gboolean gst_oss4_sink_prepare (GstAudioSink * asink, + GstRingBufferSpec * spec); +static gboolean gst_oss4_sink_unprepare (GstAudioSink * asink); +static guint gst_oss4_sink_write (GstAudioSink * asink, gpointer data, + guint length); +static guint gst_oss4_sink_delay (GstAudioSink * asink); +static void gst_oss4_sink_reset (GstAudioSink * asink); + +#define DEFAULT_DEVICE NULL +#define DEFAULT_DEVICE_NAME NULL +#define DEFAULT_MUTE FALSE +#define DEFAULT_VOLUME 1.0 +#define MAX_VOLUME 10.0 + +enum +{ + PROP_0, + PROP_DEVICE, + PROP_DEVICE_NAME, + PROP_VOLUME, + PROP_MUTE, + PROP_LAST +}; + +GST_BOILERPLATE_FULL (GstOss4Sink, gst_oss4_sink, GstAudioSink, + GST_TYPE_AUDIO_SINK, gst_oss4_sink_init_interfaces); + +static void +gst_oss4_sink_dispose (GObject * object) +{ + GstOss4Sink *osssink = GST_OSS4_SINK (object); + + if (osssink->probed_caps) { + gst_caps_unref (osssink->probed_caps); + osssink->probed_caps = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_oss4_sink_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + GstPadTemplate *templ; + + gst_element_class_set_details_simple (element_class, + "OSS v4 Audio Sink", "Sink/Audio", + "Output to a sound card via OSS version 4", + "Tim-Philipp Müller <tim centricular net>"); + + templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, + gst_oss4_audio_get_template_caps ()); + gst_element_class_add_pad_template (element_class, templ); + gst_object_unref (templ); +} + +static void +gst_oss4_sink_class_init (GstOss4SinkClass * klass) +{ + GstAudioSinkClass *audiosink_class = (GstAudioSinkClass *) klass; + GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass; + GObjectClass *gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = gst_oss4_sink_dispose; + gobject_class->finalize = gst_oss4_sink_finalize; + gobject_class->get_property = gst_oss4_sink_get_property; + gobject_class->set_property = gst_oss4_sink_set_property; + + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", + "OSS4 device (e.g. /dev/oss/hdaudio0/pcm0 or /dev/dspN) " + "(NULL = use first available playback device)", + 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)); + + basesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_oss4_sink_getcaps); + + audiosink_class->open = GST_DEBUG_FUNCPTR (gst_oss4_sink_open_func); + audiosink_class->close = GST_DEBUG_FUNCPTR (gst_oss4_sink_close); + audiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_oss4_sink_prepare); + audiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_oss4_sink_unprepare); + audiosink_class->write = GST_DEBUG_FUNCPTR (gst_oss4_sink_write); + audiosink_class->delay = GST_DEBUG_FUNCPTR (gst_oss4_sink_delay); + audiosink_class->reset = GST_DEBUG_FUNCPTR (gst_oss4_sink_reset); +} + +static void +gst_oss4_sink_init (GstOss4Sink * osssink, GstOss4SinkClass * klass) +{ + const gchar *device; + + device = g_getenv ("AUDIODEV"); + if (device == NULL) + device = DEFAULT_DEVICE; + osssink->device = g_strdup (device); + osssink->fd = -1; + osssink->bytes_per_sample = 0; + osssink->probed_caps = NULL; + osssink->device_name = NULL; + osssink->mute_volume = 100 | (100 << 8); +} + +static void +gst_oss4_sink_finalize (GObject * object) +{ + GstOss4Sink *osssink = GST_OSS4_SINK (object); + + g_free (osssink->device); + osssink->device = NULL; + + g_list_free (osssink->property_probe_list); + osssink->property_probe_list = NULL; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_oss4_sink_set_volume (GstOss4Sink * oss, gdouble volume) +{ + int ivol; + + volume = volume * 100.0; + ivol = (int) volume | ((int) volume << 8); + GST_OBJECT_LOCK (oss); + if (ioctl (oss->fd, SNDCTL_DSP_SETPLAYVOL, &ivol) < 0) { + GST_LOG_OBJECT (oss, "SETPLAYVOL failed"); + } + GST_OBJECT_UNLOCK (oss); +} + +static gdouble +gst_oss4_sink_get_volume (GstOss4Sink * oss) +{ + int ivol, lvol, rvol; + gdouble dvol = DEFAULT_VOLUME; + + GST_OBJECT_LOCK (oss); + if (ioctl (oss->fd, SNDCTL_DSP_GETPLAYVOL, &ivol) < 0) { + GST_LOG_OBJECT (oss, "GETPLAYVOL failed"); + } else { + /* Return the higher of the two volume channels, if different */ + lvol = ivol & 0xff; + rvol = (ivol >> 8) & 0xff; + dvol = MAX (lvol, rvol) / 100.0; + } + GST_OBJECT_UNLOCK (oss); + + return dvol; +} + +static void +gst_oss4_sink_set_mute (GstOss4Sink * oss, gboolean mute) +{ + int ivol; + + if (mute) { + /* + * OSSv4 does not have a per-channel mute, so simulate by setting + * the value to 0. Save the volume before doing a mute so we can + * reset the value when the user un-mutes. + */ + ivol = 0; + + GST_OBJECT_LOCK (oss); + if (ioctl (oss->fd, SNDCTL_DSP_GETPLAYVOL, &oss->mute_volume) < 0) { + GST_LOG_OBJECT (oss, "GETPLAYVOL failed"); + } + if (ioctl (oss->fd, SNDCTL_DSP_SETPLAYVOL, &ivol) < 0) { + GST_LOG_OBJECT (oss, "SETPLAYVOL failed"); + } + GST_OBJECT_UNLOCK (oss); + } else { + /* + * If the saved volume is 0, then reset it to 100. Otherwise the mute + * can get stuck. This can happen, for example, due to rounding + * errors in converting from the float to an integer. + */ + if (oss->mute_volume == 0) { + oss->mute_volume = 100 | (100 << 8); + } + GST_OBJECT_LOCK (oss); + if (ioctl (oss->fd, SNDCTL_DSP_SETPLAYVOL, &oss->mute_volume) < 0) { + GST_LOG_OBJECT (oss, "SETPLAYVOL failed"); + } + GST_OBJECT_UNLOCK (oss); + } +} + +static gboolean +gst_oss4_sink_get_mute (GstOss4Sink * oss) +{ + int ivol, lvol, rvol; + + GST_OBJECT_LOCK (oss); + if (ioctl (oss->fd, SNDCTL_DSP_GETPLAYVOL, &ivol) < 0) { + GST_LOG_OBJECT (oss, "GETPLAYVOL failed"); + lvol = rvol = 100; + } else { + lvol = ivol & 0xff; + rvol = (ivol >> 8) & 0xff; + } + GST_OBJECT_UNLOCK (oss); + + return (lvol == 0 && rvol == 0); +} + +static void +gst_oss4_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOss4Sink *oss = GST_OSS4_SINK (object); + + switch (prop_id) { + case PROP_DEVICE: + GST_OBJECT_LOCK (oss); + if (oss->fd == -1) { + g_free (oss->device); + oss->device = g_value_dup_string (value); + if (oss->probed_caps) { + gst_caps_unref (oss->probed_caps); + oss->probed_caps = NULL; + } + g_free (oss->device_name); + oss->device_name = NULL; + } else { + g_warning ("%s: can't change \"device\" property while audio sink " + "is open", GST_OBJECT_NAME (oss)); + } + GST_OBJECT_UNLOCK (oss); + break; + case PROP_VOLUME: + gst_oss4_sink_set_volume (oss, g_value_get_double (value)); + break; + case PROP_MUTE: + gst_oss4_sink_set_mute (oss, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_oss4_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstOss4Sink *oss = GST_OSS4_SINK (object); + + switch (prop_id) { + case PROP_DEVICE: + GST_OBJECT_LOCK (oss); + g_value_set_string (value, oss->device); + GST_OBJECT_UNLOCK (oss); + break; + case PROP_DEVICE_NAME: + GST_OBJECT_LOCK (oss); + if (oss->fd == -1 && oss->device != NULL) { + /* If device is set, try to retrieve the name even if we're not open */ + if (gst_oss4_sink_open (GST_AUDIO_SINK (oss), TRUE)) { + g_value_set_string (value, oss->device_name); + gst_oss4_sink_close (GST_AUDIO_SINK (oss)); + } else { + gchar *name = NULL; + + gst_oss4_property_probe_find_device_name_nofd (GST_OBJECT (oss), + oss->device, &name); + g_value_set_string (value, name); + g_free (name); + } + } else { + g_value_set_string (value, oss->device_name); + } + GST_OBJECT_UNLOCK (oss); + break; + case PROP_VOLUME: + g_value_set_double (value, gst_oss4_sink_get_volume (oss)); + break; + case PROP_MUTE: + g_value_set_boolean (value, gst_oss4_sink_get_mute (oss)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstCaps * +gst_oss4_sink_getcaps (GstBaseSink * bsink) +{ + GstOss4Sink *oss; + GstCaps *caps; + + oss = GST_OSS4_SINK (bsink); + + if (oss->fd == -1) { + caps = gst_oss4_audio_get_template_caps (); + } else if (oss->probed_caps) { + caps = gst_caps_copy (oss->probed_caps); + } else { + caps = gst_oss4_audio_probe_caps (GST_OBJECT (oss), oss->fd); + if (caps != NULL && !gst_caps_is_empty (caps)) { + oss->probed_caps = gst_caps_copy (caps); + } + } + + return caps; +} + +/* note: we must not take the object lock here unless we fix up get_property */ +static gboolean +gst_oss4_sink_open (GstAudioSink * asink, gboolean silent_errors) +{ + GstOss4Sink *oss; + gchar *device; + int mode; + + oss = GST_OSS4_SINK (asink); + + if (oss->device) + device = g_strdup (oss->device); + else + device = gst_oss4_audio_find_device (GST_OBJECT_CAST (oss)); + + /* desperate times, desperate measures */ + if (device == NULL) + device = g_strdup ("/dev/dsp0"); + + GST_INFO_OBJECT (oss, "Trying to open OSS4 device '%s'", device); + + /* we open in non-blocking mode even if we don't really want to do writes + * non-blocking because we can't be sure that this is really a genuine + * OSS4 device with well-behaved drivers etc. We really don't want to + * hang forever under any circumstances. */ + oss->fd = open (device, O_WRONLY | O_NONBLOCK, 0); + if (oss->fd == -1) { + switch (errno) { + case EBUSY: + goto busy; + case EACCES: + goto no_permission; + default: + goto open_failed; + } + } + + GST_INFO_OBJECT (oss, "Opened device '%s'", device); + + /* Make sure it's OSS4. If it's old OSS, let osssink handle it */ + if (!gst_oss4_audio_check_version (GST_OBJECT_CAST (oss), oss->fd)) + goto legacy_oss; + + /* now remove the non-blocking flag. */ + mode = fcntl (oss->fd, F_GETFL); + mode &= ~O_NONBLOCK; + if (fcntl (oss->fd, F_SETFL, mode) < 0) { + /* some drivers do no support unsetting the non-blocking flag, try to + * close/open the device then. This is racy but we error out properly. */ + GST_WARNING_OBJECT (oss, "failed to unset O_NONBLOCK (buggy driver?), " + "will try to re-open device now"); + gst_oss4_sink_close (asink); + if ((oss->fd = open (device, O_WRONLY, 0)) == -1) + goto non_block; + } + + oss->open_device = device; + + /* not using ENGINEINFO here because it sometimes returns a different and + * less useful name than AUDIOINFO for the same device */ + if (!gst_oss4_property_probe_find_device_name (GST_OBJECT (oss), oss->fd, + oss->open_device, &oss->device_name)) { + oss->device_name = NULL; + } + + /* list output routings, for informational purposes only so far */ + { + oss_mixer_enuminfo routings = { 0, }; + guint i; + + if (ioctl (oss->fd, SNDCTL_DSP_GET_PLAYTGT_NAMES, &routings) != -1) { + GST_LOG_OBJECT (oss, "%u output routings (static list: %d)", + routings.nvalues, !!(routings.version == 0)); + for (i = 0; i < routings.nvalues; ++i) { + GST_LOG_OBJECT (oss, " output routing %d: %s", i, + &routings.strings[routings.strindex[i]]); + } + } + } + + return TRUE; + + /* ERRORS */ +busy: + { + if (!silent_errors) { + GST_ELEMENT_ERROR (oss, RESOURCE, BUSY, + (_("Could not open audio device for playback. " + "Device is being used by another application.")), (NULL)); + } + g_free (device); + return FALSE; + } +no_permission: + { + if (!silent_errors) { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE, + (_("Could not open audio device for playback. " + "You don't have permission to open the device.")), + GST_ERROR_SYSTEM); + } + g_free (device); + return FALSE; + } +open_failed: + { + if (!silent_errors) { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE, + (_("Could not open audio device for playback.")), GST_ERROR_SYSTEM); + } + g_free (device); + return FALSE; + } +legacy_oss: + { + if (!silent_errors) { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE, + (_("Could not open audio device for playback. " + "This version of the Open Sound System is not supported by this " + "element.")), ("Try the 'osssink' element instead")); + } + gst_oss4_sink_close (asink); + g_free (device); + return FALSE; + } +non_block: + { + if (!silent_errors) { + GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL), + ("Unable to set device %s into non-blocking mode: %s", + oss->device, g_strerror (errno))); + } + g_free (device); + return FALSE; + } +} + +static gboolean +gst_oss4_sink_open_func (GstAudioSink * asink) +{ + return gst_oss4_sink_open (asink, FALSE); +} + +static gboolean +gst_oss4_sink_close (GstAudioSink * asink) +{ + GstOss4Sink *oss = GST_OSS4_SINK (asink); + + if (oss->fd != -1) { + GST_DEBUG_OBJECT (oss, "closing device"); + close (oss->fd); + oss->fd = -1; + } + + oss->bytes_per_sample = 0; + /* we keep the probed caps cached, at least until the device changes */ + + g_free (oss->open_device); + oss->open_device = NULL; + + g_free (oss->device_name); + oss->device_name = NULL; + + if (oss->probed_caps) { + gst_caps_unref (oss->probed_caps); + oss->probed_caps = NULL; + } + + return TRUE; +} + +static gboolean +gst_oss4_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) +{ + GstOss4Sink *oss; + + oss = GST_OSS4_SINK (asink); + + if (!gst_oss4_audio_set_format (GST_OBJECT_CAST (oss), oss->fd, spec)) { + GST_WARNING_OBJECT (oss, "Couldn't set requested format %" GST_PTR_FORMAT, + spec->caps); + return FALSE; + } + + oss->bytes_per_sample = spec->bytes_per_sample; + return TRUE; +} + +static gboolean +gst_oss4_sink_unprepare (GstAudioSink * asink) +{ + /* could do a SNDCTL_DSP_HALT, but the OSS manual recommends a close/open, + * since HALT won't properly reset some devices, apparently */ + + if (!gst_oss4_sink_close (asink)) + goto couldnt_close; + + if (!gst_oss4_sink_open_func (asink)) + goto couldnt_reopen; + + return TRUE; + + /* ERRORS */ +couldnt_close: + { + GST_DEBUG_OBJECT (asink, "Couldn't close the audio device"); + return FALSE; + } +couldnt_reopen: + { + GST_DEBUG_OBJECT (asink, "Couldn't reopen the audio device"); + return FALSE; + } +} + +static guint +gst_oss4_sink_write (GstAudioSink * asink, gpointer data, guint length) +{ + GstOss4Sink *oss; + int n; + + oss = GST_OSS4_SINK_CAST (asink); + + n = write (oss->fd, data, length); + GST_LOG_OBJECT (asink, "wrote %d/%d samples, %d bytes", + n / oss->bytes_per_sample, length / oss->bytes_per_sample, n); + + if (G_UNLIKELY (n < 0)) { + switch (errno) { + case ENOTSUP: + case EACCES:{ + /* This is the most likely cause, I think */ + GST_ELEMENT_ERROR (asink, RESOURCE, WRITE, + (_("Playback is not supported by this audio device.")), + ("write: %s (device: %s) (maybe this is an input-only device?)", + g_strerror (errno), oss->open_device)); + break; + } + default:{ + GST_ELEMENT_ERROR (asink, RESOURCE, WRITE, + (_("Audio playback error.")), + ("write: %s (device: %s)", g_strerror (errno), oss->open_device)); + break; + } + } + } + + return n; +} + +static guint +gst_oss4_sink_delay (GstAudioSink * asink) +{ + GstOss4Sink *oss; + gint delay = -1; + + oss = GST_OSS4_SINK_CAST (asink); + + GST_OBJECT_LOCK (oss); + if (ioctl (oss->fd, SNDCTL_DSP_GETODELAY, &delay) < 0 || delay < 0) { + GST_LOG_OBJECT (oss, "GETODELAY failed"); + } + GST_OBJECT_UNLOCK (oss); + + if (G_UNLIKELY (delay < 0)) /* error case */ + return 0; + + return delay / oss->bytes_per_sample; +} + +static void +gst_oss4_sink_reset (GstAudioSink * asink) +{ + /* There's nothing we can do here really: OSS can't handle access to the + * same device/fd from multiple threads and might deadlock or blow up in + * other ways if we try an ioctl SNDCTL_DSP_HALT or similar */ +} + +static void +gst_oss4_sink_init_interfaces (GType type) +{ + static const GInterfaceInfo svol_iface_info = { + NULL, NULL, NULL + }; + + g_type_add_interface_static (type, GST_TYPE_STREAM_VOLUME, &svol_iface_info); + + gst_oss4_add_property_probe_interface (type); +} diff --git a/sys/oss4/oss4-sink.h b/sys/oss4/oss4-sink.h new file mode 100644 index 0000000..b1489a7 --- /dev/null +++ b/sys/oss4/oss4-sink.h @@ -0,0 +1,64 @@ +/* GStreamer OSS4 audio sink + * Copyright (C) 2007-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_OSS4_SINK_H +#define GST_OSS4_SINK_H + + +#include <gst/gst.h> +#include <gst/audio/gstaudiosink.h> + +G_BEGIN_DECLS + +#define GST_TYPE_OSS4_SINK (gst_oss4_sink_get_type()) +#define GST_OSS4_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_SINK,GstOss4Sink)) +#define GST_OSS4_SINK_CAST(obj) ((GstOss4Sink *)(obj)) +#define GST_OSS4_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_SINK,GstOss4SinkClass)) +#define GST_IS_OSS4_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_SINK)) +#define GST_IS_OSS4_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_SINK)) + +typedef struct _GstOss4Sink GstOss4Sink; +typedef struct _GstOss4SinkClass GstOss4SinkClass; + +struct _GstOss4Sink { + GstAudioSink audio_sink; + + gchar * device; /* NULL if none was set */ + gchar * open_device; /* the device we opened */ + gchar * device_name; /* set if the device is open */ + gint fd; /* -1 if not open */ + gint bytes_per_sample; + gint mute_volume; + + GstCaps * probed_caps; + + GList * property_probe_list; +}; + +struct _GstOss4SinkClass { + GstAudioSinkClass audio_sink_class; +}; + +GType gst_oss4_sink_get_type (void); + +G_END_DECLS + +#endif /* GST_OSS4_SINK_H */ + + diff --git a/sys/oss4/oss4-soundcard.h b/sys/oss4/oss4-soundcard.h new file mode 100644 index 0000000..8b12489 --- /dev/null +++ b/sys/oss4/oss4-soundcard.h @@ -0,0 +1,2067 @@ +/* + * Purpose: The C/C++ header file that defines the OSS API. + * Description: + * This header file contains all the declarations required to compile OSS + * programs. The latest version is always installed together with OSS + * use of the latest version is strongly recommended. + * + * {!notice This header file contains many obsolete definitions + * (for compatibility with older applications that still ned them). + * Do not use this file as a reference manual of OSS. + * Please check the OSS Programmer's guide for descriptions + * of the supported API details (http://manuals.opensound.com/developer).} + */ + +#ifndef SOUNDCARD_H +#define SOUNDCARD_H + +#define COPYING40 Copyright (C) 4Front Technologies 2000-2006. Released under the BSD license. + +#if defined(__cplusplus) +#define EXTERNC extern "C" +#else +#define EXTERNC extern +#endif /* EXTERN_C_WRAPPERS */ + +#define OSS_VERSION 0x040090 // Pre 4.1 + +#define SOUND_VERSION OSS_VERSION +#define OPEN_SOUND_SYSTEM + +#if defined(__hpux) && !defined(_HPUX_SOURCE) +# error "-D_HPUX_SOURCE must be used when compiling OSS applications" +#endif + +#ifdef __hpux +#include <sys/ioctl.h> +#endif + +#ifdef linux +/* In Linux we need to be prepared for cross compiling */ +#include <linux/ioctl.h> +#else +# ifdef __FreeBSD__ +# include <sys/ioccom.h> +# else +# include <sys/ioctl.h> +# endif +#endif + +#ifndef __SIOWR +#if defined(__hpux) || (defined(_IOWR) && (defined(_AIX) || (!defined(sun) && !defined(sparc) && !defined(__INCioctlh) && !defined(__Lynx__)))) + +/* + * Make sure the ioctl macros are compatible with the ones already used + * by this operating system. + */ +#define SIOCPARM_MASK IOCPARM_MASK +#define SIOC_VOID IOC_VOID +#define SIOC_OUT IOC_OUT +#define SIOC_IN IOC_IN +#define SIOC_INOUT IOC_INOUT +#define __SIOC_SIZE _IOC_SIZE +#define __SIOC_DIR _IOC_DIR +#define __SIOC_NONE _IOC_NONE +#define __SIOC_READ _IOC_READ +#define __SIOC_WRITE _IOC_WRITE +#define __SIO _IO +#define __SIOR _IOR +#define __SIOW _IOW +#define __SIOWR _IOWR +#else + +/* #define SIOCTYPE (0xff<<8) */ +#define SIOCPARM_MASK 0x1fff /* parameters must be < 8192 bytes */ +#define SIOC_VOID 0x00000000 /* no parameters */ +#define SIOC_OUT 0x20000000 /* copy out parameters */ +#define SIOC_IN 0x40000000 /* copy in parameters */ +#define SIOC_INOUT (SIOC_IN|SIOC_OUT) + +#define __SIO(x,y) ((int)(SIOC_VOID|(x<<8)|y)) +#define __SIOR(x,y,t) ((int)(SIOC_OUT|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y)) +#define __SIOW(x,y,t) ((int)(SIOC_IN|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y)) +#define __SIOWR(x,y,t) ((int)(SIOC_INOUT|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y)) +#define __SIOC_SIZE(x) ((x>>16)&SIOCPARM_MASK) +#define __SIOC_DIR(x) (x & 0xf0000000) +#define __SIOC_NONE SIOC_VOID +#define __SIOC_READ SIOC_OUT +#define __SIOC_WRITE SIOC_IN +# endif /* _IOWR */ +#endif /* !__SIOWR */ + +#define OSS_LONGNAME_SIZE 64 +#define OSS_LABEL_SIZE 16 +#define OSS_DEVNODE_SIZE 32 +typedef char oss_longname_t[OSS_LONGNAME_SIZE]; +typedef char oss_label_t[OSS_LABEL_SIZE]; +typedef char oss_devnode_t[OSS_DEVNODE_SIZE]; + +#ifndef DISABLE_SEQUENCER +/* + **************************************************************************** + * IOCTL Commands for /dev/sequencer and /dev/music (AKA /dev/sequencer2) + * + * Note that this interface is obsolete and no longer developed. New + * applications should use /dev/midi instead. + ****************************************************************************/ +#define SNDCTL_SEQ_RESET __SIO ('Q', 0) +#define SNDCTL_SEQ_SYNC __SIO ('Q', 1) +#define SNDCTL_SYNTH_INFO __SIOWR('Q', 2, struct synth_info) +#define SNDCTL_SEQ_CTRLRATE __SIOWR('Q', 3, int) /* Set/get timer resolution (HZ) */ +#define SNDCTL_SEQ_GETOUTCOUNT __SIOR ('Q', 4, int) +#define SNDCTL_SEQ_GETINCOUNT __SIOR ('Q', 5, int) +#define SNDCTL_SEQ_PERCMODE __SIOW ('Q', 6, int) +#define SNDCTL_FM_LOAD_INSTR __SIOW ('Q', 7, struct sbi_instrument) /* Obsolete. Don't use!!!!!! */ +#define SNDCTL_SEQ_TESTMIDI __SIOW ('Q', 8, int) +#define SNDCTL_SEQ_RESETSAMPLES __SIOW ('Q', 9, int) +#define SNDCTL_SEQ_NRSYNTHS __SIOR ('Q',10, int) +#define SNDCTL_SEQ_NRMIDIS __SIOR ('Q',11, int) +#define SNDCTL_MIDI_INFO __SIOWR('Q',12, struct midi_info) /* OBSOLETE - use SNDCTL_MIDIINFO instead */ +#define SNDCTL_SEQ_THRESHOLD __SIOW ('Q',13, int) +#define SNDCTL_SYNTH_MEMAVL __SIOWR('Q',14, int) /* in=dev#, out=memsize */ +#define SNDCTL_FM_4OP_ENABLE __SIOW ('Q',15, int) /* in=dev# */ +#define SNDCTL_SEQ_PANIC __SIO ('Q',17) +#define SNDCTL_SEQ_OUTOFBAND __SIOW ('Q',18, struct seq_event_rec) +#define SNDCTL_SEQ_GETTIME __SIOR ('Q',19, int) +#define SNDCTL_SYNTH_ID __SIOWR('Q',20, struct synth_info) +#define SNDCTL_SYNTH_CONTROL __SIOWR('Q',21, struct synth_control) +#define SNDCTL_SYNTH_REMOVESAMPLE __SIOWR('Q',22, struct remove_sample) /* Reserved for future use */ +#define SNDCTL_SEQ_TIMING_ENABLE __SIO ('Q', 23) /* Enable incoming MIDI timing messages */ +#define SNDCTL_SEQ_ACTSENSE_ENABLE __SIO ('Q', 24) /* Enable incoming active sensing messages */ +#define SNDCTL_SEQ_RT_ENABLE __SIO ('Q', 25) /* Enable other incoming realtime messages */ + +typedef struct synth_control +{ + int devno; /* Synthesizer # */ + char data[4000]; /* Device spesific command/data record */ +} synth_control; + +typedef struct remove_sample +{ + int devno; /* Synthesizer # */ + int bankno; /* MIDI bank # (0=General MIDI) */ + int instrno; /* MIDI instrument number */ +} remove_sample; + +typedef struct seq_event_rec +{ + unsigned char arr[8]; +} seq_event_rec; + +#define SNDCTL_TMR_TIMEBASE __SIOWR('T', 1, int) +#define SNDCTL_TMR_START __SIO ('T', 2) +#define SNDCTL_TMR_STOP __SIO ('T', 3) +#define SNDCTL_TMR_CONTINUE __SIO ('T', 4) +#define SNDCTL_TMR_TEMPO __SIOWR('T', 5, int) +#define SNDCTL_TMR_SOURCE __SIOWR('T', 6, int) +# define TMR_INTERNAL 0x00000001 +# define TMR_EXTERNAL 0x00000002 +# define TMR_MODE_MIDI 0x00000010 +# define TMR_MODE_FSK 0x00000020 +# define TMR_MODE_CLS 0x00000040 +# define TMR_MODE_SMPTE 0x00000080 +#define SNDCTL_TMR_METRONOME __SIOW ('T', 7, int) +#define SNDCTL_TMR_SELECT __SIOW ('T', 8, int) + +/* + * Sample loading mechanism for internal synthesizers (/dev/sequencer) + * (for the .PAT format). + */ + +struct patch_info +{ + unsigned short key; /* Use WAVE_PATCH here */ +#define WAVE_PATCH _PATCHKEY(0x04) +#define GUS_PATCH WAVE_PATCH +#define WAVEFRONT_PATCH _PATCHKEY(0x06) + + short device_no; /* Synthesizer number */ + short instr_no; /* Midi pgm# */ + + unsigned int mode; +/* + * The least significant byte has the same format than the GUS .PAT + * files + */ +#define WAVE_16_BITS 0x01 /* bit 0 = 8 or 16 bit wave data. */ +#define WAVE_UNSIGNED 0x02 /* bit 1 = Signed - Unsigned data. */ +#define WAVE_LOOPING 0x04 /* bit 2 = looping enabled-1. */ +#define WAVE_BIDIR_LOOP 0x08 /* bit 3 = Set is bidirectional looping. */ +#define WAVE_LOOP_BACK 0x10 /* bit 4 = Set is looping backward. */ +#define WAVE_SUSTAIN_ON 0x20 /* bit 5 = Turn sustaining on. (Env. pts. 3) */ +#define WAVE_ENVELOPES 0x40 /* bit 6 = Enable envelopes - 1 */ +#define WAVE_FAST_RELEASE 0x80 /* bit 7 = Shut off immediately after note off */ + /* (use the env_rate/env_offs fields). */ +/* Linux specific bits */ +#define WAVE_VIBRATO 0x00010000 /* The vibrato info is valid */ +#define WAVE_TREMOLO 0x00020000 /* The tremolo info is valid */ +#define WAVE_SCALE 0x00040000 /* The scaling info is valid */ +#define WAVE_FRACTIONS 0x00080000 /* Fraction information is valid */ +/* Reserved bits */ +#define WAVE_ROM 0x40000000 /* For future use */ +#define WAVE_MULAW 0x20000000 /* For future use */ +/* Other bits must be zeroed */ + + int len; /* Size of the wave data in bytes */ + int loop_start, loop_end; /* Byte offsets from the beginning */ + +/* + * The base_freq and base_note fields are used when computing the + * playback speed for a note. The base_note defines the tone frequency + * which is heard if the sample is played using the base_freq as the + * playback speed. + * + * The low_note and high_note fields define the minimum and maximum note + * frequencies for which this sample is valid. It is possible to define + * more than one samples for an instrument number at the same time. The + * low_note and high_note fields are used to select the most suitable one. + * + * The fields base_note, high_note and low_note should contain + * the note frequency multiplied by 1000. For example value for the + * middle A is 440*1000. + */ + + unsigned int base_freq; + unsigned int base_note; + unsigned int high_note; + unsigned int low_note; + int panning; /* -128=left, 127=right */ + int detuning; + + /* Envelope. Enabled by mode bit WAVE_ENVELOPES */ + unsigned char env_rate[6]; /* GUS HW ramping rate */ + unsigned char env_offset[6]; /* 255 == 100% */ + + /* + * The tremolo, vibrato and scale info are not supported yet. + * Enable by setting the mode bits WAVE_TREMOLO, WAVE_VIBRATO or + * WAVE_SCALE + */ + + unsigned char tremolo_sweep; + unsigned char tremolo_rate; + unsigned char tremolo_depth; + + unsigned char vibrato_sweep; + unsigned char vibrato_rate; + unsigned char vibrato_depth; + + int scale_frequency; + unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */ + + int volume; + int fractions; + int reserved1; + int spare[2]; + char data[1]; /* The waveform data starts here */ +}; + +struct sysex_info +{ + short key; /* Use SYSEX_PATCH or MAUI_PATCH here */ +#define SYSEX_PATCH _PATCHKEY(0x05) +#define MAUI_PATCH _PATCHKEY(0x06) + short device_no; /* Synthesizer number */ + int len; /* Size of the sysex data in bytes */ + unsigned char data[1]; /* Sysex data starts here */ +}; + +/* + * /dev/sequencer input events. + * + * The data written to the /dev/sequencer is a stream of events. Events + * are records of 4 or 8 bytes. The first byte defines the size. + * Any number of events can be written with a write call. There + * is a set of macros for sending these events. Use these macros if you + * want to maximize portability of your program. + * + * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events. + * (All input events are currently 4 bytes long. Be prepared to support + * 8 byte events also. If you receive any event having first byte >= 128, + * it's a 8 byte event. + * + * The events are documented at the end of this file. + * + * Normal events (4 bytes) + * There is also a 8 byte version of most of the 4 byte events. The + * 8 byte one is recommended. + * + * NOTE! All 4 byte events are now obsolete. Applications should not write + * them. However 4 byte events are still used as inputs from + * /dev/sequencer (/dev/music uses only 8 byte ones). + */ +#define SEQ_NOTEOFF 0 +#define SEQ_FMNOTEOFF SEQ_NOTEOFF /* Just old name */ +#define SEQ_NOTEON 1 +#define SEQ_FMNOTEON SEQ_NOTEON +#define SEQ_WAIT TMR_WAIT_ABS +#define SEQ_PGMCHANGE 3 +#define SEQ_FMPGMCHANGE SEQ_PGMCHANGE +#define SEQ_SYNCTIMER TMR_START +#define SEQ_MIDIPUTC 5 +#define SEQ_DRUMON 6 /*** OBSOLETE ***/ +#define SEQ_DRUMOFF 7 /*** OBSOLETE ***/ +#define SEQ_ECHO TMR_ECHO /* For synching programs with output */ +#define SEQ_AFTERTOUCH 9 +#define SEQ_CONTROLLER 10 +#define SEQ_BALANCE 11 +#define SEQ_VOLMODE 12 + +/************************************ + * Midi controller numbers * + ************************************/ +/* + * Controllers 0 to 31 (0x00 to 0x1f) and + * 32 to 63 (0x20 to 0x3f) are continuous + * controllers. + * In the MIDI 1.0 these controllers are sent using + * two messages. Controller numbers 0 to 31 are used + * to send the MSB and the controller numbers 32 to 63 + * are for the LSB. Note that just 7 bits are used in MIDI bytes. + */ + +#define CTL_BANK_SELECT 0x00 +#define CTL_MODWHEEL 0x01 +#define CTL_BREATH 0x02 +/* undefined 0x03 */ +#define CTL_FOOT 0x04 +#define CTL_PORTAMENTO_TIME 0x05 +#define CTL_DATA_ENTRY 0x06 +#define CTL_MAIN_VOLUME 0x07 +#define CTL_BALANCE 0x08 +/* undefined 0x09 */ +#define CTL_PAN 0x0a +#define CTL_EXPRESSION 0x0b +/* undefined 0x0c */ +/* undefined 0x0d */ +/* undefined 0x0e */ +/* undefined 0x0f */ +#define CTL_GENERAL_PURPOSE1 0x10 +#define CTL_GENERAL_PURPOSE2 0x11 +#define CTL_GENERAL_PURPOSE3 0x12 +#define CTL_GENERAL_PURPOSE4 0x13 +/* undefined 0x14 - 0x1f */ + +/* undefined 0x20 */ +/* The controller numbers 0x21 to 0x3f are reserved for the */ +/* least significant bytes of the controllers 0x00 to 0x1f. */ +/* These controllers are not recognised by the driver. */ + +/* Controllers 64 to 69 (0x40 to 0x45) are on/off switches. */ +/* 0=OFF and 127=ON (intermediate values are possible) */ +#define CTL_DAMPER_PEDAL 0x40 +#define CTL_SUSTAIN 0x40 /* Alias */ +#define CTL_HOLD 0x40 /* Alias */ +#define CTL_PORTAMENTO 0x41 +#define CTL_SOSTENUTO 0x42 +#define CTL_SOFT_PEDAL 0x43 +/* undefined 0x44 */ +#define CTL_HOLD2 0x45 +/* undefined 0x46 - 0x4f */ + +#define CTL_GENERAL_PURPOSE5 0x50 +#define CTL_GENERAL_PURPOSE6 0x51 +#define CTL_GENERAL_PURPOSE7 0x52 +#define CTL_GENERAL_PURPOSE8 0x53 +/* undefined 0x54 - 0x5a */ +#define CTL_EXT_EFF_DEPTH 0x5b +#define CTL_TREMOLO_DEPTH 0x5c +#define CTL_CHORUS_DEPTH 0x5d +#define CTL_DETUNE_DEPTH 0x5e +#define CTL_CELESTE_DEPTH 0x5e /* Alias for the above one */ +#define CTL_PHASER_DEPTH 0x5f +#define CTL_DATA_INCREMENT 0x60 +#define CTL_DATA_DECREMENT 0x61 +#define CTL_NONREG_PARM_NUM_LSB 0x62 +#define CTL_NONREG_PARM_NUM_MSB 0x63 +#define CTL_REGIST_PARM_NUM_LSB 0x64 +#define CTL_REGIST_PARM_NUM_MSB 0x65 +/* undefined 0x66 - 0x78 */ +/* reserved 0x79 - 0x7f */ + +/* Pseudo controllers (not midi compatible) */ +#define CTRL_PITCH_BENDER 255 +#define CTRL_PITCH_BENDER_RANGE 254 +#define CTRL_EXPRESSION 253 /* Obsolete */ +#define CTRL_MAIN_VOLUME 252 /* Obsolete */ + +/* + * Volume mode defines how volumes are used + */ + +#define VOL_METHOD_ADAGIO 1 +#define VOL_METHOD_LINEAR 2 + +/* + * Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as + * input events. + */ + +/* + * Event codes 0xf0 to 0xfc are reserved for future extensions. + */ + +#define SEQ_FULLSIZE 0xfd /* Long events */ +/* + * SEQ_FULLSIZE events are used for loading patches/samples to the + * synthesizer devices. These events are passed directly to the driver + * of the associated synthesizer device. There is no limit to the size + * of the extended events. These events are not queued but executed + * immediately when the write() is called (execution can take several + * seconds of time). + * + * When a SEQ_FULLSIZE message is written to the device, it must + * be written using exactly one write() call. Other events cannot + * be mixed to the same write. + * + * For FM synths (YM3812/OPL3) use struct sbi_instrument and write it to the + * /dev/sequencer. Don't write other data together with the instrument structure + * Set the key field of the structure to FM_PATCH. The device field is used to + * route the patch to the corresponding device. + * + * For wave table use struct patch_info. Initialize the key field + * to WAVE_PATCH. + */ +#define SEQ_PRIVATE 0xfe /* Low level HW dependent events (8 bytes) */ +#define SEQ_EXTENDED 0xff /* Extended events (8 bytes) OBSOLETE */ + +/* + * Record for FM patches + */ + +typedef unsigned char sbi_instr_data[32]; + +struct sbi_instrument +{ + unsigned short key; /* FM_PATCH or OPL3_PATCH */ +#define FM_PATCH _PATCHKEY(0x01) +#define OPL3_PATCH _PATCHKEY(0x03) + short device; /* Synth# (0-4) */ + int channel; /* Program# to be initialized */ + sbi_instr_data operators; /* Register settings for operator cells (.SBI format) */ +}; + +struct synth_info +{ /* Read only */ + char name[30]; + int device; /* 0-N. INITIALIZE BEFORE CALLING */ + int synth_type; +#define SYNTH_TYPE_FM 0 +#define SYNTH_TYPE_SAMPLE 1 +#define SYNTH_TYPE_MIDI 2 /* Midi interface */ + + int synth_subtype; +#define FM_TYPE_ADLIB 0x00 +#define FM_TYPE_OPL3 0x01 +#define MIDI_TYPE_MPU401 0x401 + +#define SAMPLE_TYPE_BASIC 0x10 +#define SAMPLE_TYPE_GUS SAMPLE_TYPE_BASIC +#define SAMPLE_TYPE_WAVEFRONT 0x11 + + int perc_mode; /* No longer supported */ + int nr_voices; + int nr_drums; /* Obsolete field */ + int instr_bank_size; + unsigned int capabilities; +#define SYNTH_CAP_PERCMODE 0x00000001 /* No longer used */ +#define SYNTH_CAP_OPL3 0x00000002 /* Set if OPL3 supported */ +#define SYNTH_CAP_INPUT 0x00000004 /* Input (MIDI) device */ + int dummies[19]; /* Reserve space */ +}; + +struct sound_timer_info +{ + char name[32]; + int caps; +}; + +struct midi_info /* OBSOLETE */ +{ + char name[30]; + int device; /* 0-N. INITIALIZE BEFORE CALLING */ + unsigned int capabilities; /* To be defined later */ + int dev_type; + int dummies[18]; /* Reserve space */ +}; + +/* + * Level 2 event types for /dev/sequencer + */ + +/* + * The 4 most significant bits of byte 0 specify the class of + * the event: + * + * 0x8X = system level events, + * 0x9X = device/port specific events, event[1] = device/port, + * The last 4 bits give the subtype: + * 0x02 = Channel event (event[3] = chn). + * 0x01 = note event (event[4] = note). + * (0x01 is not used alone but always with bit 0x02). + * event[2] = MIDI message code (0x80=note off etc.) + * + */ + +#define EV_SEQ_LOCAL 0x80 +#define EV_TIMING 0x81 +#define EV_CHN_COMMON 0x92 +#define EV_CHN_VOICE 0x93 +#define EV_SYSEX 0x94 +#define EV_SYSTEM 0x95 /* MIDI system and real time messages (input only) */ +/* + * Event types 200 to 220 are reserved for application use. + * These numbers will not be used by the driver. + */ + +/* + * Events for event type EV_CHN_VOICE + */ + +#define MIDI_NOTEOFF 0x80 +#define MIDI_NOTEON 0x90 +#define MIDI_KEY_PRESSURE 0xA0 + +/* + * Events for event type EV_CHN_COMMON + */ + +#define MIDI_CTL_CHANGE 0xB0 +#define MIDI_PGM_CHANGE 0xC0 +#define MIDI_CHN_PRESSURE 0xD0 +#define MIDI_PITCH_BEND 0xE0 + +#define MIDI_SYSTEM_PREFIX 0xF0 + +/* + * Timer event types + */ +#define TMR_WAIT_REL 1 /* Time relative to the prev time */ +#define TMR_WAIT_ABS 2 /* Absolute time since TMR_START */ +#define TMR_STOP 3 +#define TMR_START 4 +#define TMR_CONTINUE 5 +#define TMR_TEMPO 6 +#define TMR_ECHO 8 +#define TMR_CLOCK 9 /* MIDI clock */ +#define TMR_SPP 10 /* Song position pointer */ +#define TMR_TIMESIG 11 /* Time signature */ + +/* + * Local event types + */ +#define LOCL_STARTAUDIO 1 +#define LOCL_STARTAUDIO2 2 +#define LOCL_STARTAUDIO3 3 +#define LOCL_STARTAUDIO4 4 + +#if (!defined(__KERNEL__) && !defined(KERNEL) && !defined(INKERNEL) && !defined(_KERNEL)) || defined(USE_SEQ_MACROS) +/* + * Some convenience macros to simplify programming of the + * /dev/sequencer interface + * + * These macros define the API which should be used when possible. + */ +#define SEQ_DECLAREBUF() SEQ_USE_EXTBUF() + +void seqbuf_dump (void); /* This function must be provided by programs */ + +EXTERNC int OSS_init (int seqfd, int buflen); +EXTERNC void OSS_seqbuf_dump (int fd, unsigned char *buf, int buflen); +EXTERNC void OSS_seq_advbuf (int len, int fd, unsigned char *buf, int buflen); +EXTERNC void OSS_seq_needbuf (int len, int fd, unsigned char *buf, + int buflen); +EXTERNC void OSS_patch_caching (int dev, int chn, int patch, int fd, + unsigned char *buf, int buflen); +EXTERNC void OSS_drum_caching (int dev, int chn, int patch, int fd, + unsigned char *buf, int buflen); +EXTERNC void OSS_write_patch (int fd, unsigned char *buf, int len); +EXTERNC int OSS_write_patch2 (int fd, unsigned char *buf, int len); + +#define SEQ_PM_DEFINES int __foo_bar___ +#ifdef OSSLIB +# define SEQ_USE_EXTBUF() \ + EXTERNC unsigned char *_seqbuf; \ + EXTERNC int _seqbuflen;EXTERNC int _seqbufptr +# define SEQ_DEFINEBUF(len) SEQ_USE_EXTBUF();static int _requested_seqbuflen=len +# define _SEQ_ADVBUF(len) OSS_seq_advbuf(len, seqfd, _seqbuf, _seqbuflen) +# define _SEQ_NEEDBUF(len) OSS_seq_needbuf(len, seqfd, _seqbuf, _seqbuflen) +# define SEQ_DUMPBUF() OSS_seqbuf_dump(seqfd, _seqbuf, _seqbuflen) + +# define SEQ_LOAD_GMINSTR(dev, instr) \ + OSS_patch_caching(dev, -1, instr, seqfd, _seqbuf, _seqbuflen) +# define SEQ_LOAD_GMDRUM(dev, drum) \ + OSS_drum_caching(dev, -1, drum, seqfd, _seqbuf, _seqbuflen) +#else /* !OSSLIB */ + +# define SEQ_LOAD_GMINSTR(dev, instr) +# define SEQ_LOAD_GMDRUM(dev, drum) + +# define SEQ_USE_EXTBUF() \ + EXTERNC unsigned char _seqbuf[]; \ + EXTERNC int _seqbuflen;EXTERNC int _seqbufptr + +#ifndef USE_SIMPLE_MACROS +/* Sample seqbuf_dump() implementation: + * + * SEQ_DEFINEBUF (2048); -- Defines a buffer for 2048 bytes + * + * int seqfd; -- The file descriptor for /dev/sequencer. + * + * void + * seqbuf_dump () + * { + * if (_seqbufptr) + * if (write (seqfd, _seqbuf, _seqbufptr) == -1) + * { + * perror ("write /dev/sequencer"); + * exit (-1); + * } + * _seqbufptr = 0; + * } + */ + +#define SEQ_DEFINEBUF(len) \ + unsigned char _seqbuf[len]; int _seqbuflen = len;int _seqbufptr = 0 +#define _SEQ_NEEDBUF(len) \ + if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump() +#define _SEQ_ADVBUF(len) _seqbufptr += len +#define SEQ_DUMPBUF seqbuf_dump +#else +/* + * This variation of the sequencer macros is used just to format one event + * using fixed buffer. + * + * The program using the macro library must define the following macros before + * using this library. + * + * #define _seqbuf name of the buffer (unsigned char[]) + * #define _SEQ_ADVBUF(len) If the applic needs to know the exact + * size of the event, this macro can be used. + * Otherwise this must be defined as empty. + * #define _seqbufptr Define the name of index variable or 0 if + * not required. + */ +#define _SEQ_NEEDBUF(len) /* empty */ +#endif +#endif /* !OSSLIB */ + +#define SEQ_VOLUME_MODE(dev, mode) \ + {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (mode);\ + _seqbuf[_seqbufptr+4] = 0;\ + _seqbuf[_seqbufptr+5] = 0;\ + _seqbuf[_seqbufptr+6] = 0;\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} + +/* + * Midi voice messages + */ + +#define _CHN_VOICE(dev, event, chn, note, parm) \ + {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = EV_CHN_VOICE;\ + _seqbuf[_seqbufptr+1] = (dev);\ + _seqbuf[_seqbufptr+2] = (event);\ + _seqbuf[_seqbufptr+3] = (chn);\ + _seqbuf[_seqbufptr+4] = (note);\ + _seqbuf[_seqbufptr+5] = (parm);\ + _seqbuf[_seqbufptr+6] = (0);\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} + +#define SEQ_START_NOTE(dev, chn, note, vol) \ + _CHN_VOICE(dev, MIDI_NOTEON, chn, note, vol) + +#define SEQ_STOP_NOTE(dev, chn, note, vol) \ + _CHN_VOICE(dev, MIDI_NOTEOFF, chn, note, vol) + +#define SEQ_KEY_PRESSURE(dev, chn, note, pressure) \ + _CHN_VOICE(dev, MIDI_KEY_PRESSURE, chn, note, pressure) + +/* + * Midi channel messages + */ + +#define _CHN_COMMON(dev, event, chn, p1, p2, w14) \ + {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = EV_CHN_COMMON;\ + _seqbuf[_seqbufptr+1] = (dev);\ + _seqbuf[_seqbufptr+2] = (event);\ + _seqbuf[_seqbufptr+3] = (chn);\ + _seqbuf[_seqbufptr+4] = (p1);\ + _seqbuf[_seqbufptr+5] = (p2);\ + *(short *)&_seqbuf[_seqbufptr+6] = (w14);\ + _SEQ_ADVBUF(8);} +/* + * SEQ_SYSEX permits sending of sysex messages. (It may look that it permits + * sending any MIDI bytes but it's absolutely not possible. Trying to do + * so _will_ cause problems with MPU401 intelligent mode). + * + * Sysex messages are sent in blocks of 1 to 6 bytes. Longer messages must be + * sent by calling SEQ_SYSEX() several times (there must be no other events + * between them). First sysex fragment must have 0xf0 in the first byte + * and the last byte (buf[len-1] of the last fragment must be 0xf7. No byte + * between these sysex start and end markers cannot be larger than 0x7f. Also + * lengths of each fragments (except the last one) must be 6. + * + * Breaking the above rules may work with some MIDI ports but is likely to + * cause fatal problems with some other devices (such as MPU401). + */ +#define SEQ_SYSEX(dev, buf, len) \ + {int ii, ll=(len); \ + unsigned char *bufp=buf;\ + if (ll>6)ll=6;\ + _SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = EV_SYSEX;\ + _seqbuf[_seqbufptr+1] = (dev);\ + for(ii=0;ii<ll;ii++)\ + _seqbuf[_seqbufptr+ii+2] = bufp[ii];\ + for(ii=ll;ii<6;ii++)\ + _seqbuf[_seqbufptr+ii+2] = 0xff;\ + _SEQ_ADVBUF(8);} + +#define SEQ_CHN_PRESSURE(dev, chn, pressure) \ + _CHN_COMMON(dev, MIDI_CHN_PRESSURE, chn, pressure, 0, 0) + +#define SEQ_SET_PATCH SEQ_PGM_CHANGE +#ifdef OSSLIB +# define SEQ_PGM_CHANGE(dev, chn, patch) \ + {OSS_patch_caching(dev, chn, patch, seqfd, _seqbuf, _seqbuflen); \ + _CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0);} +#else +# define SEQ_PGM_CHANGE(dev, chn, patch) \ + _CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0) +#endif + +#define SEQ_CONTROL(dev, chn, controller, value) \ + _CHN_COMMON(dev, MIDI_CTL_CHANGE, chn, controller, 0, value) + +#define SEQ_BENDER(dev, chn, value) \ + _CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value) + +#define SEQ_V2_X_CONTROL(dev, voice, controller, value) \ + {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (voice);\ + _seqbuf[_seqbufptr+4] = (controller);\ + _seqbuf[_seqbufptr+5] = ((value)&0xff);\ + _seqbuf[_seqbufptr+6] = ((value>>8)&0xff);\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} +/* + * The following 5 macros are incorrectly implemented and obsolete. + * Use SEQ_BENDER and SEQ_CONTROL (with proper controller) instead. + */ +#define SEQ_PITCHBEND(dev, voice, value) \ + SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER, value) +#define SEQ_BENDER_RANGE(dev, voice, value) \ + SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value) +#define SEQ_EXPRESSION(dev, voice, value) \ + SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128) +#define SEQ_MAIN_VOLUME(dev, voice, value) \ + SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100) +#define SEQ_PANNING(dev, voice, pos) \ + SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2) + +/* + * Timing and syncronization macros + */ + +#define _TIMER_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr+0] = EV_TIMING; \ + _seqbuf[_seqbufptr+1] = (ev); \ + _seqbuf[_seqbufptr+2] = 0;\ + _seqbuf[_seqbufptr+3] = 0;\ + *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \ + _SEQ_ADVBUF(8);} + +#define SEQ_START_TIMER() _TIMER_EVENT(TMR_START, 0) +#define SEQ_STOP_TIMER() _TIMER_EVENT(TMR_STOP, 0) +#define SEQ_CONTINUE_TIMER() _TIMER_EVENT(TMR_CONTINUE, 0) +#define SEQ_WAIT_TIME(ticks) _TIMER_EVENT(TMR_WAIT_ABS, ticks) +#define SEQ_DELTA_TIME(ticks) _TIMER_EVENT(TMR_WAIT_REL, ticks) +#define SEQ_ECHO_BACK(key) _TIMER_EVENT(TMR_ECHO, key) +#define SEQ_SET_TEMPO(value) _TIMER_EVENT(TMR_TEMPO, value) +#define SEQ_SONGPOS(pos) _TIMER_EVENT(TMR_SPP, pos) +#define SEQ_TIME_SIGNATURE(sig) _TIMER_EVENT(TMR_TIMESIG, sig) + +/* + * Local control events + */ + +#define _LOCAL_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr+0] = EV_SEQ_LOCAL; \ + _seqbuf[_seqbufptr+1] = (ev); \ + _seqbuf[_seqbufptr+2] = 0;\ + _seqbuf[_seqbufptr+3] = 0;\ + *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \ + _SEQ_ADVBUF(8);} + +#define SEQ_PLAYAUDIO(devmask) _LOCAL_EVENT(LOCL_STARTAUDIO, devmask) +#define SEQ_PLAYAUDIO2(devmask) _LOCAL_EVENT(LOCL_STARTAUDIO2, devmask) +#define SEQ_PLAYAUDIO3(devmask) _LOCAL_EVENT(LOCL_STARTAUDIO3, devmask) +#define SEQ_PLAYAUDIO4(devmask) _LOCAL_EVENT(LOCL_STARTAUDIO4, devmask) +/* + * Events for the level 1 interface only + */ + +#define SEQ_MIDIOUT(device, byte) {_SEQ_NEEDBUF(4);\ + _seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\ + _seqbuf[_seqbufptr+1] = (byte);\ + _seqbuf[_seqbufptr+2] = (device);\ + _seqbuf[_seqbufptr+3] = 0;\ + _SEQ_ADVBUF(4);} + +/* + * Patch loading. + */ +#ifdef OSSLIB +# define SEQ_WRPATCH(patchx, len) \ + OSS_write_patch(seqfd, (char*)(patchx), len) +# define SEQ_WRPATCH2(patchx, len) \ + OSS_write_patch2(seqfd, (char*)(patchx), len) +#else +# define SEQ_WRPATCH(patchx, len) \ + {if (_seqbufptr) SEQ_DUMPBUF();\ + if (write(seqfd, (char*)(patchx), len)==-1) \ + perror("Write patch: /dev/sequencer");} +# define SEQ_WRPATCH2(patchx, len) \ + (SEQ_DUMPBUF(), write(seqfd, (char*)(patchx), len)) +#endif + +#endif +#endif /* ifndef DISABLE_SEQUENCER */ + +/* + **************************************************************************** + * ioctl commands for the /dev/midi## + ****************************************************************************/ +#define SNDCTL_MIDI_PRETIME __SIOWR('m', 0, int) + +#if 0 +/* + * The SNDCTL_MIDI_MPUMODE and SNDCTL_MIDI_MPUCMD calls + * are completely obsolete. The hardware device (MPU-401 "intelligent mode" + * and compatibles) has disappeared from the market 10 years ago so there + * is no need for this stuff. The MPU-401 "UART" mode devices don't support + * this stuff. + */ +typedef struct +{ + unsigned char cmd; + char nr_args, nr_returns; + unsigned char data[30]; +} mpu_command_rec; + +#define SNDCTL_MIDI_MPUMODE __SIOWR('m', 1, int) +#define SNDCTL_MIDI_MPUCMD __SIOWR('m', 2, mpu_command_rec) +#endif + +/* + * SNDCTL_MIDI_MTCINPUT turns on a mode where OSS automatically inserts + * MTC quarter frame messages (F1 xx) to the input. + * The argument is the MTC mode: + * + * -1 = Turn MTC messages OFF (default) + * 24 = 24 FPS + * 25 = 25 FPS + * 29 = 30 FPS drop frame + * 30 = 30 FPS + * + * Note that 25 FPS mode is probably the only mode that is supported. Other + * modes may be supported in the future versions of OSS, 25 FPS is handy + * because it generates 25*4=100 quarter frame messages per second which + * matches the usual 100 HZ system timer rate). + * + * The quarter frame timer will be reset to 0:00:00:00.0 at the moment this + * ioctl is made. + */ +#define SNDCTL_MIDI_MTCINPUT __SIOWR('m', 3, int) + +/* + * MTC/SMPTE time code record (for future use) + */ +typedef struct +{ + unsigned char hours, minutes, seconds, frames, qframes; + char direction; +#define MTC_DIR_STOPPED 0 +#define MTC_DIR_FORWARD 1 +#define MTC_DIR_BACKWARD -1 + unsigned char time_code_type; + unsigned int flags; +} oss_mtc_data_t; + +#define SNDCTL_MIDI_SETMODE __SIOWR('m', 6, int) +# define MIDI_MODE_TRADITIONAL 0 +# define MIDI_MODE_TIMED 1 /* Input times are in MIDI ticks */ +# define MIDI_MODE_TIMED_ABS 2 /* Input times are absolute (usecs) */ + +/* + * Packet header for MIDI_MODE_TIMED and MIDI_MODE_TIMED_ABS + */ +typedef unsigned long long oss_midi_time_t; /* Variable type for MIDI time (clock ticks) */ + +typedef struct +{ + int magic; /* Initialize to MIDI_HDR_MAGIC */ +#define MIDI_HDR_MAGIC -1 + unsigned short event_type; +#define MIDI_EV_WRITE 0 /* Write or read (with payload) */ +#define MIDI_EV_TEMPO 1 +#define MIDI_EV_ECHO 2 +#define MIDI_EV_START 3 +#define MIDI_EV_STOP 4 +#define MIDI_EV_CONTINUE 5 +#define MIDI_EV_XPRESSWRITE 6 +#define MIDI_EV_TIMEBASE 7 +#define MIDI_EV_DEVCTL 8 /* Device control read/write */ + unsigned short options; +#define MIDI_OPT_NONE 0x0000 +#define MIDI_OPT_TIMED 0x0001 +#define MIDI_OPT_CONTINUATION 0x0002 +#define MIDI_OPT_USECTIME 0x0004 /* Time is absolute (in usecs) */ +#define MIDI_OPT_BUSY 0x0008 /* Reserved for internal use */ + oss_midi_time_t time; + int parm; + int filler[3]; /* Fur future expansion - init to zeros */ +} midi_packet_header_t; +/* + * MIDI_PAYLOAD_SIZE is the maximum size of one MIDI input chunk. It must be + * less (or equal) than 1024 which is the read size recommended in the + * documentation. TODO: Explain this better. + */ +#define MIDI_PAYLOAD_SIZE 1000 + +typedef struct +{ + midi_packet_header_t hdr; + unsigned char payload[MIDI_PAYLOAD_SIZE]; +} midi_packet_t; + +#define SNDCTL_MIDI_TIMEBASE __SIOWR('m', 7, int) +#define SNDCTL_MIDI_TEMPO __SIOWR('m', 8, int) +/* + * User land MIDI servers (synths) can use SNDCTL_MIDI_SET_LATENCY + * to request MIDI events to be sent to them in advance. The parameter + * (in microseconds) tells how much before the events are submitted. + * + * This feature is only valid for loopback devices and possibly some other + * types of virtual devices. + */ +#define SNDCTL_MIDI_SET_LATENCY __SIOW ('m', 9, int) +/* + **************************************************************************** + * IOCTL commands for /dev/dsp + ****************************************************************************/ + +#define SNDCTL_DSP_HALT __SIO ('P', 0) +#define SNDCTL_DSP_RESET SNDCTL_DSP_HALT /* Old name */ +#define SNDCTL_DSP_SYNC __SIO ('P', 1) +#define SNDCTL_DSP_SPEED __SIOWR('P', 2, int) + +/* SNDCTL_DSP_STEREO is obsolete - use SNDCTL_DSP_CHANNELS instead */ +#define SNDCTL_DSP_STEREO __SIOWR('P', 3, int) +/* SNDCTL_DSP_STEREO is obsolete - use SNDCTL_DSP_CHANNELS instead */ + +#define SNDCTL_DSP_GETBLKSIZE __SIOWR('P', 4, int) +#define SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT +#define SNDCTL_DSP_CHANNELS __SIOWR('P', 6, int) +#define SNDCTL_DSP_POST __SIO ('P', 8) +#define SNDCTL_DSP_SUBDIVIDE __SIOWR('P', 9, int) +#define SNDCTL_DSP_SETFRAGMENT __SIOWR('P',10, int) + +/* Audio data formats (Note! U8=8 and S16_LE=16 for compatibility) */ +#define SNDCTL_DSP_GETFMTS __SIOR ('P',11, int) /* Returns a mask */ +#define SNDCTL_DSP_SETFMT __SIOWR('P',5, int) /* Selects ONE fmt */ +# define AFMT_QUERY 0x00000000 /* Return current fmt */ +# define AFMT_MU_LAW 0x00000001 +# define AFMT_A_LAW 0x00000002 +# define AFMT_IMA_ADPCM 0x00000004 +# define AFMT_U8 0x00000008 +# define AFMT_S16_LE 0x00000010 /* Little endian signed 16 */ +# define AFMT_S16_BE 0x00000020 /* Big endian signed 16 */ +# define AFMT_S8 0x00000040 +# define AFMT_U16_LE 0x00000080 /* Little endian U16 */ +# define AFMT_U16_BE 0x00000100 /* Big endian U16 */ +# define AFMT_MPEG 0x00000200 /* MPEG (2) audio */ + +/* AC3 _compressed_ bitstreams (See Programmer's Guide for details). */ +# define AFMT_AC3 0x00000400 +/* Ogg Vorbis _compressed_ bit streams */ +# define AFMT_VORBIS 0x00000800 + +/* 32 bit formats (MSB aligned) formats */ +# define AFMT_S32_LE 0x00001000 +# define AFMT_S32_BE 0x00002000 + +/* Reserved for _native_ endian double precision IEEE floating point */ +# define AFMT_FLOAT 0x00004000 + +/* 24 bit formats (LSB aligned in 32 bit word) formats */ +# define AFMT_S24_LE 0x00008000 +# define AFMT_S24_BE 0x00010000 + +/* + * S/PDIF raw format. In this format the S/PDIF frames (including all + * control and user bits) are included in the data stream. Each sample + * is stored in a 32 bit frame (see IEC-958 for more info). This format + * is supported by very few devices and it's only usable for purposes + * where full access to the control/user bits is required (real time control). + */ +# define AFMT_SPDIF_RAW 0x00020000 + +/* 24 bit packed (3 byte) little endian format (USB compatibility) */ +# define AFMT_S24_PACKED 0x00040000 + + +/* + * Some big endian/little endian handling macros (native endian and opposite + * endian formats). The usage of these macros is described in the OSS + * Programmer's Manual. + */ + +#if defined(_AIX) || defined(AIX) || defined(sparc) || defined(__hppa) || defined(PPC) || defined(__powerpc__) && !defined(i386) && !defined(__i386) && !defined(__i386__) + +/* Big endian machines */ +# define _PATCHKEY(id) (0xfd00|id) +# define AFMT_S16_NE AFMT_S16_BE +# define AFMT_U16_NE AFMT_U16_BE +# define AFMT_S32_NE AFMT_S32_BE +# define AFMT_S24_NE AFMT_S24_BE +# define AFMT_S16_OE AFMT_S16_LE +# define AFMT_S32_OE AFMT_S32_LE +# define AFMT_S24_OE AFMT_S24_LE +#else +# define _PATCHKEY(id) ((id<<8)|0xfd) +# define AFMT_S16_NE AFMT_S16_LE +# define AFMT_U16_NE AFMT_U16_LE +# define AFMT_S32_NE AFMT_S32_LE +# define AFMT_S24_NE AFMT_S24_LE +# define AFMT_S16_OE AFMT_S16_BE +# define AFMT_S32_OE AFMT_S32_BE +# define AFMT_S24_OE AFMT_S24_BE +#endif +/* + * Buffer status queries. + */ +typedef struct audio_buf_info +{ + int fragments; /* # of available fragments (partially usend ones not counted) */ + int fragstotal; /* Total # of fragments allocated */ + int fragsize; /* Size of a fragment in bytes */ + int bytes; /* Available space in bytes (includes partially used fragments) */ + /* Note! 'bytes' could be more than fragments*fragsize */ +} audio_buf_info; + +#define SNDCTL_DSP_GETOSPACE __SIOR ('P',12, audio_buf_info) +#define SNDCTL_DSP_GETISPACE __SIOR ('P',13, audio_buf_info) +#define SNDCTL_DSP_GETCAPS __SIOR ('P',15, int) +# define PCM_CAP_REVISION 0x000000ff /* Bits for revision level (0 to 255) */ +# define PCM_CAP_DUPLEX 0x00000100 /* Full duplex record/playback */ +# define PCM_CAP_REALTIME 0x00000200 /* Not in use */ +# define PCM_CAP_BATCH 0x00000400 /* Device has some kind of */ + /* internal buffers which may */ + /* cause some delays and */ + /* decrease precision of timing */ +# define PCM_CAP_COPROC 0x00000800 /* Has a coprocessor */ + /* Sometimes it's a DSP */ + /* but usually not */ +# define PCM_CAP_TRIGGER 0x00001000 /* Supports SETTRIGGER */ +# define PCM_CAP_MMAP 0x00002000 /* Supports mmap() */ +# define PCM_CAP_MULTI 0x00004000 /* Supports multiple open */ +# define PCM_CAP_BIND 0x00008000 /* Supports binding to front/rear/center/lfe */ +# define PCM_CAP_INPUT 0x00010000 /* Supports recording */ +# define PCM_CAP_OUTPUT 0x00020000 /* Supports playback */ +# define PCM_CAP_VIRTUAL 0x00040000 /* Virtual device */ +/* 0x00040000 and 0x00080000 reserved for future use */ + +/* Analog/digital control capabilities */ +# define PCM_CAP_ANALOGOUT 0x00100000 +# define PCM_CAP_ANALOGIN 0x00200000 +# define PCM_CAP_DIGITALOUT 0x00400000 +# define PCM_CAP_DIGITALIN 0x00800000 +# define PCM_CAP_ADMASK 0x00f00000 +/* + * NOTE! (capabilities & PCM_CAP_ADMASK)==0 means just that the + * digital/analog interface control features are not supported by the + * device/driver. However the device still supports analog, digital or + * both inputs/outputs (depending on the device). See the OSS Programmer's + * Guide for full details. + */ +# define PCM_CAP_SHADOW 0x01000000 /* "Shadow" device */ + +/* + * Preferred channel usage. These bits can be used to + * give recommendations to the application. Used by few drivers. + * For example if ((caps & DSP_CH_MASK) == DSP_CH_MONO) means that + * the device works best in mono mode. However it doesn't necessarily mean + * that the device cannot be used in stereo. These bits should only be used + * by special applications such as multi track hard disk recorders to find + * out the initial setup. However the user should be able to override this + * selection. + * + * To find out which modes are actually supported the application should + * try to select them using SNDCTL_DSP_CHANNELS. + */ +# define DSP_CH_MASK 0x06000000 /* Mask */ +# define DSP_CH_ANY 0x00000000 /* No preferred mode */ +# define DSP_CH_MONO 0x02000000 +# define DSP_CH_STEREO 0x04000000 +# define DSP_CH_MULTI 0x06000000 /* More than two channels */ + +# define PCM_CAP_HIDDEN 0x08000000 /* Hidden device */ +# define PCM_CAP_FREERATE 0x10000000 +# define PCM_CAP_MODEM 0x20000000 /* Modem device */ +# define PCM_CAP_DEFAULT 0x40000000 /* "Default" device */ + +/* + * The PCM_CAP_* capability names were known as DSP_CAP_* prior OSS 4.0 + * so it's necessary to define the older names too. + */ +#define DSP_CAP_ADMASK PCM_CAP_ADMASK +#define DSP_CAP_ANALOGIN PCM_CAP_ANALOGIN +#define DSP_CAP_ANALOGOUT PCM_CAP_ANALOGOUT +#define DSP_CAP_BATCH PCM_CAP_BATCH +#define DSP_CAP_BIND PCM_CAP_BIND +#define DSP_CAP_COPROC PCM_CAP_COPROC +#define DSP_CAP_DEFAULT PCM_CAP_DEFAULT +#define DSP_CAP_DIGITALIN PCM_CAP_DIGITALIN +#define DSP_CAP_DIGITALOUT PCM_CAP_DIGITALOUT +#define DSP_CAP_DUPLEX PCM_CAP_DUPLEX +#define DSP_CAP_FREERATE PCM_CAP_FREERATE +#define DSP_CAP_HIDDEN PCM_CAP_HIDDEN +#define DSP_CAP_INPUT PCM_CAP_INPUT +#define DSP_CAP_MMAP PCM_CAP_MMAP +#define DSP_CAP_MODEM PCM_CAP_MODEM +#define DSP_CAP_MULTI PCM_CAP_MULTI +#define DSP_CAP_OUTPUT PCM_CAP_OUTPUT +#define DSP_CAP_REALTIME PCM_CAP_REALTIME +#define DSP_CAP_REVISION PCM_CAP_REVISION +#define DSP_CAP_SHADOW PCM_CAP_SHADOW +#define DSP_CAP_TRIGGER PCM_CAP_TRIGGER +#define DSP_CAP_VIRTUAL PCM_CAP_VIRTUAL + +#define SNDCTL_DSP_GETTRIGGER __SIOR ('P',16, int) +#define SNDCTL_DSP_SETTRIGGER __SIOW ('P',16, int) +# define PCM_ENABLE_INPUT 0x00000001 +# define PCM_ENABLE_OUTPUT 0x00000002 + +typedef struct count_info +{ + unsigned int bytes; /* Total # of bytes processed */ + int blocks; /* # of fragment transitions since last time */ + int ptr; /* Current DMA pointer value */ +} count_info; + +#define SNDCTL_DSP_GETIPTR __SIOR ('P',17, count_info) +#define SNDCTL_DSP_GETOPTR __SIOR ('P',18, count_info) + +typedef struct buffmem_desc +{ + unsigned *buffer; + int size; +} buffmem_desc; +#define SNDCTL_DSP_SETSYNCRO __SIO ('P', 21) +#define SNDCTL_DSP_SETDUPLEX __SIO ('P', 22) + +#define SNDCTL_DSP_PROFILE __SIOW ('P', 23, int) /* OBSOLETE */ +#define APF_NORMAL 0 /* Normal applications */ +#define APF_NETWORK 1 /* Underruns probably caused by an "external" delay */ +#define APF_CPUINTENS 2 /* Underruns probably caused by "overheating" the CPU */ + +#define SNDCTL_DSP_GETODELAY __SIOR ('P', 23, int) + +typedef struct audio_errinfo +{ + int play_underruns; + int rec_overruns; + unsigned int play_ptradjust; + unsigned int rec_ptradjust; + int play_errorcount; + int rec_errorcount; + int play_lasterror; + int rec_lasterror; + int play_errorparm; + int rec_errorparm; + int filler[16]; +} audio_errinfo; + +#define SNDCTL_DSP_GETPLAYVOL __SIOR ('P', 24, int) +#define SNDCTL_DSP_SETPLAYVOL __SIOWR('P', 24, int) +#define SNDCTL_DSP_GETERROR __SIOR ('P', 25, audio_errinfo) +/* + **************************************************************************** + * Digital interface (S/PDIF) control interface + */ + +typedef struct oss_digital_control +{ + unsigned int caps; +#define DIG_CBITIN_NONE 0x00000000 +#define DIG_CBITIN_LIMITED 0x00000001 +#define DIG_CBITIN_DATA 0x00000002 +#define DIG_CBITIN_BYTE0 0x00000004 +#define DIG_CBITIN_FULL 0x00000008 +#define DIG_CBITIN_MASK 0x0000000f +#define DIG_CBITOUT_NONE 0x00000000 +#define DIG_CBITOUT_LIMITED 0x00000010 +#define DIG_CBITOUT_BYTE0 0x00000020 +#define DIG_CBITOUT_FULL 0x00000040 +#define DIG_CBITOUT_DATA 0x00000080 +#define DIG_CBITOUT_MASK 0x000000f0 +#define DIG_UBITIN 0x00000100 +#define DIG_UBITOUT 0x00000200 +#define DIG_VBITOUT 0x00000400 +#define DIG_OUTRATE 0x00000800 +#define DIG_INRATE 0x00001000 +#define DIG_INBITS 0x00002000 +#define DIG_OUTBITS 0x00004000 +#define DIG_EXACT 0x00010000 +#define DIG_PRO 0x00020000 +#define DIG_CONSUMER 0x00040000 +#define DIG_PASSTHROUGH 0x00080000 +#define DIG_OUTSEL 0x00100000 + + unsigned int valid; +#define VAL_CBITIN 0x00000001 +#define VAL_UBITIN 0x00000002 +#define VAL_CBITOUT 0x00000004 +#define VAL_UBITOUT 0x00000008 +#define VAL_ISTATUS 0x00000010 +#define VAL_IRATE 0x00000020 +#define VAL_ORATE 0x00000040 +#define VAL_INBITS 0x00000080 +#define VAL_OUTBITS 0x00000100 +#define VAL_REQUEST 0x00000200 +#define VAL_OUTSEL 0x00000400 + +#define VAL_OUTMASK (VAL_CBITOUT|VAL_UBITOUT|VAL_ORATE|VAL_OUTBITS|VAL_OUTSEL) + + unsigned int request, param; +#define SPD_RQ_PASSTHROUGH 1 + + unsigned char cbitin[24]; + unsigned char ubitin[24]; + unsigned char cbitout[24]; + unsigned char ubitout[24]; + + unsigned int outsel; +#define OUTSEL_DIGITAL 1 +#define OUTSEL_ANALOG 2 +#define OUTSEL_BOTH (OUTSEL_DIGITAL|OUTSEL_ANALOG) + + int in_data; /* Audio/data if autodetectable by the receiver */ +#define IND_UNKNOWN 0 +#define IND_AUDIO 1 +#define IND_DATA 2 + + int in_locked; /* Receiver locked */ +#define LOCK_NOT_INDICATED 0 +#define LOCK_UNLOCKED 1 +#define LOCK_LOCKED 2 + + int in_quality; /* Input signal quality */ +#define IN_QUAL_NOT_INDICATED 0 +#define IN_QUAL_POOR 1 +#define IN_QUAL_GOOD 2 + + int in_vbit, out_vbit; /* V bits */ +#define VBIT_NOT_INDICATED 0 +#define VBIT_OFF 1 +#define VBIT_ON 2 + + unsigned int in_errors; /* Various input error conditions */ +#define INERR_CRC 0x0001 +#define INERR_QCODE_CRC 0x0002 +#define INERR_PARITY 0x0004 +#define INERR_BIPHASE 0x0008 + + int srate_in, srate_out; + int bits_in, bits_out; + + int filler[32]; +} oss_digital_control; + +#define SNDCTL_DSP_READCTL __SIOWR('P', 26, oss_digital_control) +#define SNDCTL_DSP_WRITECTL __SIOWR('P', 27, oss_digital_control) + +/* + **************************************************************************** + * Sync groups for audio devices + */ +typedef struct oss_syncgroup +{ + int id; + int mode; + int filler[16]; +} oss_syncgroup; + +#define SNDCTL_DSP_SYNCGROUP __SIOWR('P', 28, oss_syncgroup) +#define SNDCTL_DSP_SYNCSTART __SIOW ('P', 29, int) + +/* + ************************************************************************** + * "cooked" mode enables software based conversions for sample rate, sample + * format (bits) and number of channels (mono/stereo). These conversions are + * required with some devices that support only one sample rate or just stereo + * to let the applications to use other formats. The cooked mode is enabled by + * default. However it's necessary to disable this mode when mmap() is used or + * when very deterministic timing is required. SNDCTL_DSP_COOKEDMODE is an + * optional call introduced in OSS 3.9.6f. It's _error return must be ignored_ + * since normally this call will return erno=EINVAL. + * + * SNDCTL_DSP_COOKEDMODE must be called immediately after open before doing + * anything else. Otherwise the call will not have any effect. + */ +#define SNDCTL_DSP_COOKEDMODE __SIOW ('P', 30, int) + +/* + ************************************************************************** + * SNDCTL_DSP_SILENCE and SNDCTL_DSP_SKIP are new calls in OSS 3.99.0 + * that can be used to implement pause/continue during playback (no effect + * on recording). + */ +#define SNDCTL_DSP_SILENCE __SIO ('P', 31) +#define SNDCTL_DSP_SKIP __SIO ('P', 32) +/* + **************************************************************************** + * Abort transfer (reset) functions for input and output + */ +#define SNDCTL_DSP_HALT_INPUT __SIO ('P', 33) +#define SNDCTL_DSP_RESET_INPUT SNDCTL_DSP_HALT_INPUT /* Old name */ +#define SNDCTL_DSP_HALT_OUTPUT __SIO ('P', 34) +#define SNDCTL_DSP_RESET_OUTPUT SNDCTL_DSP_HALT_OUTPUT /* Old name */ +/* + **************************************************************************** + * Low water level control + */ +#define SNDCTL_DSP_LOW_WATER __SIOW ('P', 34, int) + +/* + **************************************************************************** + * 64 bit pointer support. Only available in environments that support + * the 64 bit (long long) integer type. + */ +#ifndef OSS_NO_LONG_LONG +typedef struct +{ + long long samples; + int fifo_samples; + int filler[32]; /* For future use */ +} oss_count_t; + +#define SNDCTL_DSP_CURRENT_IPTR __SIOR ('P', 35, oss_count_t) +#define SNDCTL_DSP_CURRENT_OPTR __SIOR ('P', 36, oss_count_t) +#endif + +/* + **************************************************************************** + * Interface for selecting recording sources and playback output routings. + */ +#define SNDCTL_DSP_GET_RECSRC_NAMES __SIOR ('P', 37, oss_mixer_enuminfo) +#define SNDCTL_DSP_GET_RECSRC __SIOR ('P', 38, int) +#define SNDCTL_DSP_SET_RECSRC __SIOWR('P', 38, int) + +#define SNDCTL_DSP_GET_PLAYTGT_NAMES __SIOR ('P', 39, oss_mixer_enuminfo) +#define SNDCTL_DSP_GET_PLAYTGT __SIOR ('P', 40, int) +#define SNDCTL_DSP_SET_PLAYTGT __SIOWR('P', 40, int) +#define SNDCTL_DSP_GETRECVOL __SIOR ('P', 41, int) +#define SNDCTL_DSP_SETRECVOL __SIOWR('P', 41, int) + +/* + *************************************************************************** + * Some calls for setting the channel assignment with multi channel devices + * (see the manual for details). + */ +#ifndef OSS_NO_LONG_LONG +#define SNDCTL_DSP_GET_CHNORDER __SIOR ('P', 42, unsigned long long) +#define SNDCTL_DSP_SET_CHNORDER __SIOWR('P', 42, unsigned long long) +# define CHID_UNDEF 0 +# define CHID_L 1 +# define CHID_R 2 +# define CHID_C 3 +# define CHID_LFE 4 +# define CHID_LS 5 +# define CHID_RS 6 +# define CHID_LR 7 +# define CHID_RR 8 +#define CHNORDER_UNDEF 0x0000000000000000ULL +#define CHNORDER_NORMAL 0x0000000087654321ULL +#endif + +#define MAX_PEAK_CHANNELS 128 +typedef unsigned short oss_peaks_t[MAX_PEAK_CHANNELS]; +#define SNDCTL_DSP_GETIPEAKS __SIOR('P', 43, oss_peaks_t) +#define SNDCTL_DSP_GETOPEAKS __SIOR('P', 44, oss_peaks_t) + +#define SNDCTL_DSP_POLICY __SIOW('P', 45, int) /* See the manual */ + +/* + **************************************************************************** + * Few ioctl calls that are not official parts of OSS. They have been used + * by few freeware implementations of OSS. + */ +#define SNDCTL_DSP_GETCHANNELMASK __SIOWR('P', 64, int) +#define SNDCTL_DSP_BIND_CHANNEL __SIOWR('P', 65, int) +# define DSP_BIND_QUERY 0x00000000 +# define DSP_BIND_FRONT 0x00000001 +# define DSP_BIND_SURR 0x00000002 +# define DSP_BIND_CENTER_LFE 0x00000004 +# define DSP_BIND_HANDSET 0x00000008 +# define DSP_BIND_MIC 0x00000010 +# define DSP_BIND_MODEM1 0x00000020 +# define DSP_BIND_MODEM2 0x00000040 +# define DSP_BIND_I2S 0x00000080 +# define DSP_BIND_SPDIF 0x00000100 +# define DSP_BIND_REAR 0x00000200 + +#ifdef sun +/* Not part of OSS. Reserved for internal use by Solaris */ +#define X_SADA_GET_PLAYTGT_MASK __SIOR ('P', 66, int) +#define X_SADA_GET_PLAYTGT __SIOR ('P', 67, int) +#define X_SADA_SET_PLAYTGT __SIOWR('P', 68, int) +#endif + +#ifndef NO_LEGACY_MIXER +/* + **************************************************************************** + * IOCTL commands for the "legacy " /dev/mixer API (obsolete) + * + * Mixer controls + * + * There can be up to 20 different analog mixer channels. The + * SOUND_MIXER_NRDEVICES gives the currently supported maximum. + * The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells + * the devices supported by the particular mixer. + * + * {!notice This "legacy" mixer API is obsolete. It has been superceded + * by a new one (see below). + */ + +#define SOUND_MIXER_NRDEVICES 28 +#define SOUND_MIXER_VOLUME 0 +#define SOUND_MIXER_BASS 1 +#define SOUND_MIXER_TREBLE 2 +#define SOUND_MIXER_SYNTH 3 +#define SOUND_MIXER_PCM 4 +#define SOUND_MIXER_SPEAKER 5 +#define SOUND_MIXER_LINE 6 +#define SOUND_MIXER_MIC 7 +#define SOUND_MIXER_CD 8 +#define SOUND_MIXER_IMIX 9 /* Recording monitor */ +#define SOUND_MIXER_ALTPCM 10 +#define SOUND_MIXER_RECLEV 11 /* Recording level */ +#define SOUND_MIXER_IGAIN 12 /* Input gain */ +#define SOUND_MIXER_OGAIN 13 /* Output gain */ +/* + * Some soundcards have three line level inputs (line, aux1 and aux2). + * Since each card manufacturer has assigned different meanings to + * these inputs, it's impractical to assign specific meanings + * (eg line, cd, synth etc.) to them. + */ +#define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */ +#define SOUND_MIXER_LINE2 15 /* Input source 2 (aux2) */ +#define SOUND_MIXER_LINE3 16 /* Input source 3 (line) */ +#define SOUND_MIXER_DIGITAL1 17 /* Digital I/O 1 */ +#define SOUND_MIXER_DIGITAL2 18 /* Digital I/O 2 */ +#define SOUND_MIXER_DIGITAL3 19 /* Digital I/O 3 */ +#define SOUND_MIXER_PHONE 20 /* Phone */ +#define SOUND_MIXER_MONO 21 /* Mono Output */ +#define SOUND_MIXER_VIDEO 22 /* Video/TV (audio) in */ +#define SOUND_MIXER_RADIO 23 /* Radio in */ +#define SOUND_MIXER_DEPTH 24 /* Surround depth */ +#define SOUND_MIXER_REARVOL 25 /* Rear/Surround speaker vol */ +#define SOUND_MIXER_CENTERVOL 26 /* Center/LFE speaker vol */ +#define SOUND_MIXER_SIDEVOL 27 /* Side-Surround (8speaker) vol */ + +/* + * Warning: SOUND_MIXER_SURRVOL is an old name of SOUND_MIXER_SIDEVOL. + * They are both assigned to the same mixer control. Don't + * use both control names in the same program/driver. + */ +#define SOUND_MIXER_SURRVOL SOUND_MIXER_SIDEVOL + +/* Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX) */ +/* Not counted to SOUND_MIXER_NRDEVICES, but use the same number space */ +#define SOUND_ONOFF_MIN 28 +#define SOUND_ONOFF_MAX 30 + +/* Note! Number 31 cannot be used since the sign bit is reserved */ +#define SOUND_MIXER_NONE 31 + +/* + * The following unsupported macros are no longer functional. + * Use SOUND_MIXER_PRIVATE# macros in future. + */ +#define SOUND_MIXER_ENHANCE SOUND_MIXER_NONE +#define SOUND_MIXER_MUTE SOUND_MIXER_NONE +#define SOUND_MIXER_LOUD SOUND_MIXER_NONE + +#define SOUND_DEVICE_LABELS \ + {"Vol ", "Bass ", "Treble", "Synth", "Pcm ", "Speaker ", "Line ", \ + "Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \ + "Aux1", "Aux2", "Aux3", "Digital1", "Digital2", "Digital3", \ + "Phone", "Mono", "Video", "Radio", "Depth", \ + "Rear", "Center", "Side"} + +#define SOUND_DEVICE_NAMES \ + {"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \ + "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \ + "aux1", "aux2", "aux3", "dig1", "dig2", "dig3", \ + "phone", "mono", "video", "radio", "depth", \ + "rear", "center", "side"} + +/* Device bitmask identifiers */ + +#define SOUND_MIXER_RECSRC 0xff /* Arg contains a bit for each recording source */ +#define SOUND_MIXER_DEVMASK 0xfe /* Arg contains a bit for each supported device */ +#define SOUND_MIXER_RECMASK 0xfd /* Arg contains a bit for each supported recording source */ +#define SOUND_MIXER_CAPS 0xfc +# define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only one recording source at a time */ +# define SOUND_CAP_NOLEGACY 0x00000004 /* For internal use only */ +# define SOUND_CAP_NORECSRC 0x00000008 +#define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */ + +/* OSS/Free ONLY */ +#define SOUND_MIXER_OUTSRC 0xfa /* Arg contains a bit for each input source to output */ +#define SOUND_MIXER_OUTMASK 0xf9 /* Arg contains a bit for each supported input source to output */ +/* OSS/Free ONLY */ + +/* Device mask bits */ + +#define SOUND_MASK_VOLUME (1 << SOUND_MIXER_VOLUME) +#define SOUND_MASK_BASS (1 << SOUND_MIXER_BASS) +#define SOUND_MASK_TREBLE (1 << SOUND_MIXER_TREBLE) +#define SOUND_MASK_SYNTH (1 << SOUND_MIXER_SYNTH) +#define SOUND_MASK_PCM (1 << SOUND_MIXER_PCM) +#define SOUND_MASK_SPEAKER (1 << SOUND_MIXER_SPEAKER) +#define SOUND_MASK_LINE (1 << SOUND_MIXER_LINE) +#define SOUND_MASK_MIC (1 << SOUND_MIXER_MIC) +#define SOUND_MASK_CD (1 << SOUND_MIXER_CD) +#define SOUND_MASK_IMIX (1 << SOUND_MIXER_IMIX) +#define SOUND_MASK_ALTPCM (1 << SOUND_MIXER_ALTPCM) +#define SOUND_MASK_RECLEV (1 << SOUND_MIXER_RECLEV) +#define SOUND_MASK_IGAIN (1 << SOUND_MIXER_IGAIN) +#define SOUND_MASK_OGAIN (1 << SOUND_MIXER_OGAIN) +#define SOUND_MASK_LINE1 (1 << SOUND_MIXER_LINE1) +#define SOUND_MASK_LINE2 (1 << SOUND_MIXER_LINE2) +#define SOUND_MASK_LINE3 (1 << SOUND_MIXER_LINE3) +#define SOUND_MASK_DIGITAL1 (1 << SOUND_MIXER_DIGITAL1) +#define SOUND_MASK_DIGITAL2 (1 << SOUND_MIXER_DIGITAL2) +#define SOUND_MASK_DIGITAL3 (1 << SOUND_MIXER_DIGITAL3) +#define SOUND_MASK_MONO (1 << SOUND_MIXER_MONO) +#define SOUND_MASK_PHONE (1 << SOUND_MIXER_PHONE) +#define SOUND_MASK_RADIO (1 << SOUND_MIXER_RADIO) +#define SOUND_MASK_VIDEO (1 << SOUND_MIXER_VIDEO) +#define SOUND_MASK_DEPTH (1 << SOUND_MIXER_DEPTH) +#define SOUND_MASK_REARVOL (1 << SOUND_MIXER_REARVOL) +#define SOUND_MASK_CENTERVOL (1 << SOUND_MIXER_CENTERVOL) +#define SOUND_MASK_SIDEVOL (1 << SOUND_MIXER_SIDEVOL) + +/* Note! SOUND_MASK_SURRVOL is alias of SOUND_MASK_SIDEVOL */ +#define SOUND_MASK_SURRVOL (1 << SOUND_MIXER_SIDEVOL) + +/* Obsolete macros */ +#define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE) +#define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE) +#define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD) + +#define MIXER_READ(dev) __SIOR('M', dev, int) +#define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME) +#define SOUND_MIXER_READ_BASS MIXER_READ(SOUND_MIXER_BASS) +#define SOUND_MIXER_READ_TREBLE MIXER_READ(SOUND_MIXER_TREBLE) +#define SOUND_MIXER_READ_SYNTH MIXER_READ(SOUND_MIXER_SYNTH) +#define SOUND_MIXER_READ_PCM MIXER_READ(SOUND_MIXER_PCM) +#define SOUND_MIXER_READ_SPEAKER MIXER_READ(SOUND_MIXER_SPEAKER) +#define SOUND_MIXER_READ_LINE MIXER_READ(SOUND_MIXER_LINE) +#define SOUND_MIXER_READ_MIC MIXER_READ(SOUND_MIXER_MIC) +#define SOUND_MIXER_READ_CD MIXER_READ(SOUND_MIXER_CD) +#define SOUND_MIXER_READ_IMIX MIXER_READ(SOUND_MIXER_IMIX) +#define SOUND_MIXER_READ_ALTPCM MIXER_READ(SOUND_MIXER_ALTPCM) +#define SOUND_MIXER_READ_RECLEV MIXER_READ(SOUND_MIXER_RECLEV) +#define SOUND_MIXER_READ_IGAIN MIXER_READ(SOUND_MIXER_IGAIN) +#define SOUND_MIXER_READ_OGAIN MIXER_READ(SOUND_MIXER_OGAIN) +#define SOUND_MIXER_READ_LINE1 MIXER_READ(SOUND_MIXER_LINE1) +#define SOUND_MIXER_READ_LINE2 MIXER_READ(SOUND_MIXER_LINE2) +#define SOUND_MIXER_READ_LINE3 MIXER_READ(SOUND_MIXER_LINE3) + +/* Obsolete macros */ +#define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE) +#define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE) +#define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD) + +#define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC) +#define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK) +#define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK) +#define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS) +#define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS) + +#define MIXER_WRITE(dev) __SIOWR('M', dev, int) +#define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME) +#define SOUND_MIXER_WRITE_BASS MIXER_WRITE(SOUND_MIXER_BASS) +#define SOUND_MIXER_WRITE_TREBLE MIXER_WRITE(SOUND_MIXER_TREBLE) +#define SOUND_MIXER_WRITE_SYNTH MIXER_WRITE(SOUND_MIXER_SYNTH) +#define SOUND_MIXER_WRITE_PCM MIXER_WRITE(SOUND_MIXER_PCM) +#define SOUND_MIXER_WRITE_SPEAKER MIXER_WRITE(SOUND_MIXER_SPEAKER) +#define SOUND_MIXER_WRITE_LINE MIXER_WRITE(SOUND_MIXER_LINE) +#define SOUND_MIXER_WRITE_MIC MIXER_WRITE(SOUND_MIXER_MIC) +#define SOUND_MIXER_WRITE_CD MIXER_WRITE(SOUND_MIXER_CD) +#define SOUND_MIXER_WRITE_IMIX MIXER_WRITE(SOUND_MIXER_IMIX) +#define SOUND_MIXER_WRITE_ALTPCM MIXER_WRITE(SOUND_MIXER_ALTPCM) +#define SOUND_MIXER_WRITE_RECLEV MIXER_WRITE(SOUND_MIXER_RECLEV) +#define SOUND_MIXER_WRITE_IGAIN MIXER_WRITE(SOUND_MIXER_IGAIN) +#define SOUND_MIXER_WRITE_OGAIN MIXER_WRITE(SOUND_MIXER_OGAIN) +#define SOUND_MIXER_WRITE_LINE1 MIXER_WRITE(SOUND_MIXER_LINE1) +#define SOUND_MIXER_WRITE_LINE2 MIXER_WRITE(SOUND_MIXER_LINE2) +#define SOUND_MIXER_WRITE_LINE3 MIXER_WRITE(SOUND_MIXER_LINE3) + +/* Obsolete macros */ +#define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE) +#define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE) +#define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD) + +#define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC) + +typedef struct mixer_info /* OBSOLETE */ +{ + char id[16]; + char name[32]; + int modify_counter; + int card_number; + int port_number; + char handle[32]; +} mixer_info; + +/* SOUND_MIXER_INFO is obsolete - use SNDCTL_MIXERINFO instead */ +#define SOUND_MIXER_INFO __SIOR ('M', 101, mixer_info) + +/* + * Two ioctls for special souncard function (OSS/Free only) + */ +#define SOUND_MIXER_AGC _SIOWR('M', 103, int) +#define SOUND_MIXER_3DSE _SIOWR('M', 104, int) +/* + * The SOUND_MIXER_PRIVATE# commands can be redefined by low level drivers. + * These features can be used when accessing device specific features. + */ +#define SOUND_MIXER_PRIVATE1 __SIOWR('M', 111, int) +#define SOUND_MIXER_PRIVATE2 __SIOWR('M', 112, int) +#define SOUND_MIXER_PRIVATE3 __SIOWR('M', 113, int) +#define SOUND_MIXER_PRIVATE4 __SIOWR('M', 114, int) +#define SOUND_MIXER_PRIVATE5 __SIOWR('M', 115, int) + +/* The following two controls were never implemented and they should not be used. */ +#define SOUND_MIXER_READ_MAINVOL __SIOR ('M', 116, int) +#define SOUND_MIXER_WRITE_MAINVOL __SIOWR('M', 116, int) + +/* + * SOUND_MIXER_GETLEVELS and SOUND_MIXER_SETLEVELS calls can be used + * for querying current mixer settings from the driver and for loading + * default volume settings _prior_ activating the mixer (loading + * doesn't affect current state of the mixer hardware). These calls + * are for internal use by the driver software only. + */ + +typedef struct mixer_vol_table +{ + int num; /* Index to volume table */ + char name[32]; + int levels[32]; +} mixer_vol_table; + +#define SOUND_MIXER_GETLEVELS __SIOWR('M', 116, mixer_vol_table) +#define SOUND_MIXER_SETLEVELS __SIOWR('M', 117, mixer_vol_table) + +#define OSS_GETVERSION __SIOR ('M', 118, int) + +/* + * Calls to set/get the recording gain for the currently active + * recording source. These calls automatically map to the right control. + * Note that these calls are not supported by all drivers. In this case + * the call will return -1 with errno set to EINVAL + * + * The _MONGAIN work in similar way but set/get the monitoring gain for + * the currently selected recording source. + */ +#define SOUND_MIXER_READ_RECGAIN __SIOR ('M', 119, int) +#define SOUND_MIXER_WRITE_RECGAIN __SIOWR('M', 119, int) +#define SOUND_MIXER_READ_MONGAIN __SIOR ('M', 120, int) +#define SOUND_MIXER_WRITE_MONGAIN __SIOWR('M', 120, int) + +/* The following call is for driver development time purposes. It's not + * present in any released drivers. + */ +typedef unsigned char oss_reserved_t[512]; +#define SOUND_MIXER_RESERVED __SIOWR('M', 121, oss_reserved_t) +#endif /* ifndef NO_LEGACY_MIXER */ + +/* + ************************************************************************* + * The "new" mixer API of OSS 4.0 and later. + * + * This improved mixer API makes it possible to access every possible feature + * of every possible device. However you should read the mixer programming + * section of the OSS API Developer's Manual. There is no chance that you + * could use this interface correctly just by examining this header. + */ + +typedef struct oss_sysinfo +{ + char product[32]; /* For example OSS/Free, OSS/Linux or OSS/Solaris */ + char version[32]; /* For example 4.0a */ + int versionnum; /* See OSS_GETVERSION */ + char options[128]; /* Reserved */ + + int numaudios; /* # of audio/dsp devices */ + int openedaudio[8]; /* Bit mask telling which audio devices are busy */ + + int numsynths; /* # of availavle synth devices */ + int nummidis; /* # of available MIDI ports */ + int numtimers; /* # of available timer devices */ + int nummixers; /* # of mixer devices */ + + int openedmidi[8]; /* Bit mask telling which midi devices are busy */ + int numcards; /* Number of sound cards in the system */ + int numaudioengines; /* Number of audio engines in the system */ + char license[16]; /* For example "GPL" or "CDDL" */ + int filler[236]; /* For future expansion (set to -1) */ +} oss_sysinfo; + +typedef struct oss_mixext +{ + int dev; /* Mixer device number */ + int ctrl; /* Controller number */ + int type; /* Entry type */ +# define MIXT_DEVROOT 0 /* Device root entry */ +# define MIXT_GROUP 1 /* Controller group */ +# define MIXT_ONOFF 2 /* OFF (0) or ON (1) */ +# define MIXT_ENUM 3 /* Enumerated (0 to maxvalue) */ +# define MIXT_MONOSLIDER 4 /* Mono slider (0 to 255) */ +# define MIXT_STEREOSLIDER 5 /* Stereo slider (dual 0 to 255) */ +# define MIXT_MESSAGE 6 /* (Readable) textual message */ +# define MIXT_MONOVU 7 /* VU meter value (mono) */ +# define MIXT_STEREOVU 8 /* VU meter value (stereo) */ +# define MIXT_MONOPEAK 9 /* VU meter peak value (mono) */ +# define MIXT_STEREOPEAK 10 /* VU meter peak value (stereo) */ +# define MIXT_RADIOGROUP 11 /* Radio button group */ +# define MIXT_MARKER 12 /* Separator between normal and extension entries */ +# define MIXT_VALUE 13 /* Decimal value entry */ +# define MIXT_HEXVALUE 14 /* Hexadecimal value entry */ +# define MIXT_MONODB 15 /* OBSOLETE */ +# define MIXT_STEREODB 16 /* OBSOLETE */ +# define MIXT_SLIDER 17 /* Slider (mono) with full (31 bit) postitive integer range */ +# define MIXT_3D 18 + +/* + * Sliders with range expanded to 15 bits per channel (0-32767) + */ +# define MIXT_MONOSLIDER16 19 +# define MIXT_STEREOSLIDER16 20 +# define MIXT_MUTE 21 /* Mute=1, unmute=0 */ + + /**************************************************************/ + + /* Possible value range (minvalue to maxvalue) */ + /* Note that maxvalue may also be smaller than minvalue */ + int maxvalue; + int minvalue; + + int flags; +# define MIXF_READABLE 0x00000001 /* Has readable value */ +# define MIXF_WRITEABLE 0x00000002 /* Has writeable value */ +# define MIXF_POLL 0x00000004 /* May change itself */ +# define MIXF_HZ 0x00000008 /* Herz scale */ +# define MIXF_STRING 0x00000010 /* Use dynamic extensions for value */ +# define MIXF_DYNAMIC 0x00000010 /* Supports dynamic extensions */ +# define MIXF_OKFAIL 0x00000020 /* Interpret value as 1=OK, 0=FAIL */ +# define MIXF_FLAT 0x00000040 /* Flat vertical space requirements */ +# define MIXF_LEGACY 0x00000080 /* Legacy mixer control group */ +# define MIXF_CENTIBEL 0x00000100 /* Centibel (0.1 dB) step size */ +# define MIXF_DECIBEL 0x00000200 /* Step size of 1 dB */ +# define MIXF_MAINVOL 0x00000400 /* Main volume control */ +# define MIXF_PCMVOL 0x00000800 /* PCM output volume control */ +# define MIXF_RECVOL 0x00001000 /* PCM recording volume control */ +# define MIXF_MONVOL 0x00002000 /* Input->output monitor volume */ +# define MIXF_WIDE 0x00004000 /* Enum control has wide labels */ +# define MIXF_DESCR 0x00008000 /* Description (tooltip) available */ + char id[16]; /* Mnemonic ID (mainly for internal use) */ + int parent; /* Entry# of parent (group) node (-1 if root) */ + + int dummy; /* Internal use */ + + int timestamp; + + char data[64]; /* Misc data (entry type dependent) */ + unsigned char enum_present[32]; /* Mask of allowed enum values */ + int control_no; /* SOUND_MIXER_VOLUME..SOUND_MIXER_MIDI */ + /* (-1 means not indicated) */ + +/* + * The desc field is reserved for internal purposes of OSS. It should not be + * used by applications. + */ + unsigned int desc; +#define MIXEXT_SCOPE_MASK 0x0000003f +#define MIXEXT_SCOPE_OTHER 0x00000000 +#define MIXEXT_SCOPE_INPUT 0x00000001 +#define MIXEXT_SCOPE_OUTPUT 0x00000002 +#define MIXEXT_SCOPE_MONITOR 0x00000003 +#define MIXEXT_SCOPE_RECSWITCH 0x00000004 + + char extname[32]; + int update_counter; + int rgbcolor; /* 0 means default color (not black) . Otherwise 24 bit RGB color */ + int filler[6]; +} oss_mixext; + +/* + * Recommended colors to be used in the rgbcolor field. These match the + * colors used as the audio jack colors in HD audio motherboards. + */ +#define OSS_RGB_BLUE 0x7aabde // Light blue +#define OSS_RGB_GREEN 0xb3c98c // Lime green +#define OSS_RGB_PINK 0xe88c99 +#define OSS_RGB_GRAY 0xd1ccc4 +#define OSS_RGB_BLACK 0x2b2926 // Light black +#define OSS_RGB_ORANGE 0xe89e47 +#define OSS_RGB_RED 0xff0000 +#define OSS_RGB_YELLOW 0xffff00 +#define OSS_RGB_PURPLE 0x800080 +#define OSS_RGB_WHITE 0xf8f8ff + +typedef struct oss_mixext_root +{ + char id[16]; + char name[48]; +} oss_mixext_root; + +typedef struct oss_mixer_value +{ + int dev; + int ctrl; + int value; + int flags; /* Reserved for future use. Initialize to 0 */ + int timestamp; /* Must be set to oss_mixext.timestamp */ + int filler[8]; /* Reserved for future use. Initialize to 0 */ +} oss_mixer_value; + +#define OSS_ENUM_MAXVALUE 255 +#define OSS_ENUM_STRINGSIZE 3000 +typedef struct oss_mixer_enuminfo +{ + int dev; + int ctrl; + int nvalues; + int version; /* Read the manual */ + short strindex[OSS_ENUM_MAXVALUE]; + char strings[OSS_ENUM_STRINGSIZE]; +} oss_mixer_enuminfo; + +#define OPEN_READ PCM_ENABLE_INPUT +#define OPEN_WRITE PCM_ENABLE_OUTPUT +#define OPEN_READWRITE (OPEN_READ|OPEN_WRITE) + +typedef struct oss_audioinfo +{ + int dev; /* Audio device number */ + char name[64]; + int busy; /* 0, OPEN_READ, OPEN_WRITE or OPEN_READWRITE */ + int pid; + int caps; /* PCM_CAP_INPUT, PCM_CAP_OUTPUT */ + int iformats, oformats; + int magic; /* Reserved for internal use */ + char cmd[64]; /* Command using the device (if known) */ + int card_number; + int port_number; + int mixer_dev; + int legacy_device; /* Obsolete field. Replaced by devnode */ + int enabled; /* 1=enabled, 0=device not ready at this moment */ + int flags; /* For internal use only - no practical meaning */ + int min_rate, max_rate; /* Sample rate limits */ + int min_channels, max_channels; /* Number of channels supported */ + int binding; /* DSP_BIND_FRONT, etc. 0 means undefined */ + int rate_source; + char handle[32]; +#define OSS_MAX_SAMPLE_RATES 20 /* Cannot be changed */ + unsigned int nrates, rates[OSS_MAX_SAMPLE_RATES]; /* Please read the manual before using these */ + oss_longname_t song_name; /* Song name (if given) */ + oss_label_t label; /* Device label (if given) */ + int latency; /* In usecs, -1=unknown */ + oss_devnode_t devnode; /* Device special file name (absolute path) */ + int next_play_engine; /* Read the documentation for more info */ + int next_rec_engine; /* Read the documentation for more info */ + int filler[184]; +} oss_audioinfo; + +typedef struct oss_mixerinfo +{ + int dev; + char id[16]; + char name[32]; + int modify_counter; + int card_number; + int port_number; + char handle[32]; + int magic; /* Reserved */ + int enabled; /* Reserved */ + int caps; +#define MIXER_CAP_VIRTUAL 0x00000001 +#define MIXER_CAP_LAYOUT_B 0x00000002 /* For internal use only */ +#define MIXER_CAP_NARROW 0x00000004 /* Conserve horiz space */ + int flags; /* Reserved */ + int nrext; + /* + * The priority field can be used to select the default (motherboard) + * mixer device. The mixer with the highest priority is the + * most preferred one. -2 or less means that this device cannot be used + * as the default mixer. + */ + int priority; + oss_devnode_t devnode; /* Device special file name (absolute path) */ + int legacy_device; + int filler[245]; /* Reserved */ +} oss_mixerinfo; + +typedef struct oss_midi_info +{ + int dev; /* Midi device number */ + char name[64]; + int busy; /* 0, OPEN_READ, OPEN_WRITE or OPEN_READWRITE */ + int pid; + char cmd[64]; /* Command using the device (if known) */ + int caps; +#define MIDI_CAP_MPU401 0x00000001 /**** OBSOLETE ****/ +#define MIDI_CAP_INPUT 0x00000002 +#define MIDI_CAP_OUTPUT 0x00000004 +#define MIDI_CAP_INOUT (MIDI_CAP_INPUT|MIDI_CAP_OUTPUT) +#define MIDI_CAP_VIRTUAL 0x00000008 /* Pseudo device */ +#define MIDI_CAP_MTCINPUT 0x00000010 /* Supports SNDCTL_MIDI_MTCINPUT */ +#define MIDI_CAP_CLIENT 0x00000020 /* Virtual client side device */ +#define MIDI_CAP_SERVER 0x00000040 /* Virtual server side device */ +#define MIDI_CAP_INTERNAL 0x00000080 /* Internal (synth) device */ +#define MIDI_CAP_EXTERNAL 0x00000100 /* external (MIDI port) device */ +#define MIDI_CAP_PTOP 0x00000200 /* Point to point link to one device */ +#define MIDI_CAP_MTC 0x00000400 /* MTC/SMPTE (control) device */ + int magic; /* Reserved for internal use */ + int card_number; + int port_number; + int enabled; /* 1=enabled, 0=device not ready at this moment */ + int flags; /* For internal use only - no practical meaning */ + char handle[32]; + oss_longname_t song_name; /* Song name (if known) */ + oss_label_t label; /* Device label (if given) */ + int latency; /* In usecs, -1=unknown */ + oss_devnode_t devnode; /* Device special file name (absolute path) */ + int legacy_device; /* Legacy device mapping */ + int filler[235]; +} oss_midi_info; + +typedef struct oss_card_info +{ + int card; + char shortname[16]; + char longname[128]; + int flags; + char hw_info[400]; + int intr_count, ack_count; + int filler[154]; +} oss_card_info; + +#define SNDCTL_SYSINFO __SIOR ('X', 1, oss_sysinfo) +#define OSS_SYSINFO SNDCTL_SYSINFO /* Old name */ + +#define SNDCTL_MIX_NRMIX __SIOR ('X', 2, int) +#define SNDCTL_MIX_NREXT __SIOWR('X', 3, int) +#define SNDCTL_MIX_EXTINFO __SIOWR('X', 4, oss_mixext) +#define SNDCTL_MIX_READ __SIOWR('X', 5, oss_mixer_value) +#define SNDCTL_MIX_WRITE __SIOWR('X', 6, oss_mixer_value) + +#define SNDCTL_AUDIOINFO __SIOWR('X', 7, oss_audioinfo) +#define SNDCTL_MIX_ENUMINFO __SIOWR('X', 8, oss_mixer_enuminfo) +#define SNDCTL_MIDIINFO __SIOWR('X', 9, oss_midi_info) +#define SNDCTL_MIXERINFO __SIOWR('X',10, oss_mixerinfo) +#define SNDCTL_CARDINFO __SIOWR('X',11, oss_card_info) +#define SNDCTL_ENGINEINFO __SIOWR('X',12, oss_audioinfo) +#define SNDCTL_AUDIOINFO_EX __SIOWR('X',13, oss_audioinfo) + +#define SNDCTL_MIX_DESCRIPTION __SIOWR('X',14, oss_mixer_enuminfo) + +/* ioctl codes 'X', 200-255 are reserved for internal use */ + +/* + * Few more "globally" available ioctl calls. + */ +#define SNDCTL_SETSONG __SIOW ('Y', 2, oss_longname_t) +#define SNDCTL_GETSONG __SIOR ('Y', 2, oss_longname_t) +#define SNDCTL_SETNAME __SIOW ('Y', 3, oss_longname_t) +#define SNDCTL_SETLABEL __SIOW ('Y', 4, oss_label_t) +#define SNDCTL_GETLABEL __SIOR ('Y', 4, oss_label_t) +/* + * The "new" mixer API definitions end here. + *************************************** + */ + +/* + ********************************************************* + * Few routines that are included in -lOSSlib + * + * At this moment this interface is not used. OSSlib contains just + * stubs that call the related system calls directly. + */ +#ifdef OSSLIB +extern int osslib_open (const char *path, int flags, int dummy); +extern void osslib_close (int fd); +extern int osslib_write (int fd, const void *buf, int count); +extern int osslib_read (int fd, void *buf, int count); +extern int osslib_ioctl (int fd, unsigned int request, void *arg); +#else +# define osslib_open open +# define osslib_close close +# define osslib_write write +# define osslib_read read +# define osslib_ioctl ioctl +#endif + +#if 1 +#define SNDCTL_DSP_NONBLOCK __SIO ('P',14) /* Obsolete. Not supported any more */ +#endif + +#if 1 +/* + * Some obsolete macros that are not part of Open Sound System API. + */ +#define SOUND_PCM_READ_RATE SOUND_PCM_READ_RATE_is_obsolete +#define SOUND_PCM_READ_BITS SOUND_PCM_READ_BITS_is_obsolete +#define SOUND_PCM_READ_CHANNELS SOUND_PCM_READ_CHANNELS_is_obsolete +#define SOUND_PCM_WRITE_RATE SOUND_PCM_WRITE_RATE_is_obsolet_use_SNDCTL_DSP_SPEED_instead +#define SOUND_PCM_WRITE_CHANNELS SOUND_PCM_WRITE_CHANNELS_is_obsolete_use_SNDCTL_DSP_CHANNELS_instead +#define SOUND_PCM_WRITE_BITS SOUND_PCM_WRITE_BITS_is_obsolete_use_SNDCTL_DSP_SETFMT_instead +#define SOUND_PCM_POST SOUND_PCM_POST_is_obsolete_use_SNDCTL_DSP_POST_instead +#define SOUND_PCM_RESET SOUND_PCM_RESET_is_obsolete_use_SNDCTL_DSP_HALT_instead +#define SOUND_PCM_SYNC SOUND_PCM_SYNC_is_obsolete_use_SNDCTL_DSP_SYNC_instead +#define SOUND_PCM_SUBDIVIDE SOUND_PCM_SUBDIVIDE_is_obsolete_use_SNDCTL_DSP_SUBDIVIDE_instead +#define SOUND_PCM_SETFRAGMENT SOUND_PCM_SETFRAGMENT_is_obsolete_use_SNDCTL_DSP_SETFRAGMENT_instead +#define SOUND_PCM_GETFMTS SOUND_PCM_GETFMTS_is_obsolete_use_SNDCTL_DSP_GETFMTS_instead +#define SOUND_PCM_SETFMT SOUND_PCM_SETFMT_is_obsolete_use_SNDCTL_DSP_SETFMT_instead +#define SOUND_PCM_GETOSPACE SOUND_PCM_GETOSPACE_is_obsolete_use_SNDCTL_DSP_GETOSPACE_instead +#define SOUND_PCM_GETISPACE SOUND_PCM_GETISPACE_is_obsolete_use_SNDCTL_DSP_GETISPACE_instead +#define SOUND_PCM_NONBLOCK SOUND_PCM_NONBLOCK_is_obsolete_use_SNDCTL_DSP_NONBLOCK_instead +#define SOUND_PCM_GETCAPS SOUND_PCM_GETCAPS_is_obsolete_use_SNDCTL_DSP_GETCAPS_instead +#define SOUND_PCM_GETTRIGGER SOUND_PCM_GETTRIGGER_is_obsolete_use_SNDCTL_DSP_GETTRIGGER_instead +#define SOUND_PCM_SETTRIGGER SOUND_PCM_SETTRIGGER_is_obsolete_use_SNDCTL_DSP_SETTRIGGER_instead +#define SOUND_PCM_SETSYNCRO SOUND_PCM_SETSYNCRO_is_obsolete_use_SNDCTL_DSP_SETSYNCRO_instead +#define SOUND_PCM_GETIPTR SOUND_PCM_GETIPTR_is_obsolete_use_SNDCTL_DSP_GETIPTR_instead +#define SOUND_PCM_GETOPTR SOUND_PCM_GETOPTR_is_obsolete_use_SNDCTL_DSP_GETOPTR_instead +#define SOUND_PCM_MAPINBUF SOUND_PCM_MAPINBUF_is_obsolete_use_SNDCTL_DSP_MAPINBUF_instead +#define SOUND_PCM_MAPOUTBUF SOUND_PCM_MAPOUTBUF_is_obsolete_use_SNDCTL_DSP_MAPOUTBUF_instead +#endif + +#endif diff --git a/sys/oss4/oss4-source.c b/sys/oss4/oss4-source.c new file mode 100644 index 0000000..eadb4c5 --- /dev/null +++ b/sys/oss4/oss4-source.c @@ -0,0 +1,997 @@ +/* GStreamer OSS4 audio source + * Copyright (C) 2007-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. + */ + +/** + * SECTION:element-oss4src + * + * This element lets you record sound using the Open Sound System (OSS) + * version 4. + * + * <refsect2> + * <title>Example pipelines</title> + * |[ + * gst-launch -v oss4src ! queue ! audioconvert ! vorbisenc ! oggmux ! filesink location=mymusic.ogg + * ]| will record sound from your sound card using OSS4 and encode it to an + * Ogg/Vorbis file (this will only work if your mixer settings are right + * and the right inputs areenabled etc.) + * </refsect2> + * + * Since: 0.10.7 + */ + +/* FIXME: make sure we're not doing ioctls from the app thread (e.g. via the + * mixer interface) while recording */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> + +#include <gst/interfaces/mixer.h> +#include <gst/gst-i18n-plugin.h> + +#define NO_LEGACY_MIXER +#include "oss4-audio.h" +#include "oss4-source.h" +#include "oss4-property-probe.h" +#include "oss4-soundcard.h" + +#define GST_OSS4_SOURCE_IS_OPEN(src) (GST_OSS4_SOURCE(src)->fd != -1) + +GST_DEBUG_CATEGORY_EXTERN (oss4src_debug); +#define GST_CAT_DEFAULT oss4src_debug + +#define DEFAULT_DEVICE NULL +#define DEFAULT_DEVICE_NAME NULL + +enum +{ + PROP_0, + PROP_DEVICE, + PROP_DEVICE_NAME +}; + +static void gst_oss4_source_init_interfaces (GType type); + +GST_BOILERPLATE_FULL (GstOss4Source, gst_oss4_source, GstAudioSrc, + GST_TYPE_AUDIO_SRC, gst_oss4_source_init_interfaces); + +static void gst_oss4_source_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_oss4_source_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); + +static void gst_oss4_source_dispose (GObject * object); +static void gst_oss4_source_finalize (GstOss4Source * osssrc); + +static GstCaps *gst_oss4_source_getcaps (GstBaseSrc * bsrc); + +static gboolean gst_oss4_source_open (GstAudioSrc * asrc, + gboolean silent_errors); +static gboolean gst_oss4_source_open_func (GstAudioSrc * asrc); +static gboolean gst_oss4_source_close (GstAudioSrc * asrc); +static gboolean gst_oss4_source_prepare (GstAudioSrc * asrc, + GstRingBufferSpec * spec); +static gboolean gst_oss4_source_unprepare (GstAudioSrc * asrc); +static guint gst_oss4_source_read (GstAudioSrc * asrc, gpointer data, + guint length); +static guint gst_oss4_source_delay (GstAudioSrc * asrc); +static void gst_oss4_source_reset (GstAudioSrc * asrc); + +static void +gst_oss4_source_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + GstPadTemplate *templ; + + gst_element_class_set_details_simple (element_class, + "OSS v4 Audio Source", "Source/Audio", + "Capture from a sound card via OSS version 4", + "Tim-Philipp Müller <tim centricular net>"); + + templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + gst_oss4_audio_get_template_caps ()); + gst_element_class_add_pad_template (element_class, templ); + gst_object_unref (templ); +} + +static void +gst_oss4_source_class_init (GstOss4SourceClass * klass) +{ + GObjectClass *gobject_class; + GstBaseSrcClass *gstbasesrc_class; + GstAudioSrcClass *gstaudiosrc_class; + + gobject_class = (GObjectClass *) klass; + gstbasesrc_class = (GstBaseSrcClass *) klass; + gstaudiosrc_class = (GstAudioSrcClass *) klass; + + gobject_class->dispose = gst_oss4_source_dispose; + gobject_class->finalize = (GObjectFinalizeFunc) gst_oss4_source_finalize; + gobject_class->get_property = gst_oss4_source_get_property; + gobject_class->set_property = gst_oss4_source_set_property; + + gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_oss4_source_getcaps); + + gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_oss4_source_open_func); + gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_oss4_source_prepare); + gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_oss4_source_unprepare); + gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_oss4_source_close); + gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_oss4_source_read); + gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_oss4_source_delay); + gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_oss4_source_reset); + + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", + "OSS4 device (e.g. /dev/oss/hdaudio0/pcm0 or /dev/dspN) " + "(NULL = use first available device)", + 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)); +} + +static void +gst_oss4_source_init (GstOss4Source * osssrc, GstOss4SourceClass * g_class) +{ + const gchar *device; + + device = g_getenv ("AUDIODEV"); + if (device == NULL) + device = DEFAULT_DEVICE; + + osssrc->fd = -1; + osssrc->device = g_strdup (device); + osssrc->device_name = g_strdup (DEFAULT_DEVICE_NAME); + osssrc->device_name = NULL; +} + +static void +gst_oss4_source_finalize (GstOss4Source * oss) +{ + g_free (oss->device); + oss->device = NULL; + + g_list_free (oss->property_probe_list); + oss->property_probe_list = NULL; + + G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (oss)); +} + +static void +gst_oss4_source_dispose (GObject * object) +{ + GstOss4Source *oss = GST_OSS4_SOURCE (object); + + if (oss->probed_caps) { + gst_caps_unref (oss->probed_caps); + oss->probed_caps = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_oss4_source_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOss4Source *oss; + + oss = GST_OSS4_SOURCE (object); + + switch (prop_id) { + case PROP_DEVICE: + GST_OBJECT_LOCK (oss); + if (oss->fd == -1) { + g_free (oss->device); + oss->device = g_value_dup_string (value); + g_free (oss->device_name); + oss->device_name = NULL; + } else { + g_warning ("%s: can't change \"device\" property while audio source " + "is open", GST_OBJECT_NAME (oss)); + } + GST_OBJECT_UNLOCK (oss); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_oss4_source_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstOss4Source *oss; + + oss = GST_OSS4_SOURCE (object); + + switch (prop_id) { + case PROP_DEVICE: + GST_OBJECT_LOCK (oss); + g_value_set_string (value, oss->device); + GST_OBJECT_UNLOCK (oss); + break; + case PROP_DEVICE_NAME: + GST_OBJECT_LOCK (oss); + /* If device is set, try to retrieve the name even if we're not open */ + if (oss->fd == -1 && oss->device != NULL) { + if (gst_oss4_source_open (GST_AUDIO_SRC (oss), TRUE)) { + g_value_set_string (value, oss->device_name); + gst_oss4_source_close (GST_AUDIO_SRC (oss)); + } else { + gchar *name = NULL; + + gst_oss4_property_probe_find_device_name_nofd (GST_OBJECT (oss), + oss->device, &name); + g_value_set_string (value, name); + g_free (name); + } + } else { + g_value_set_string (value, oss->device_name); + } + + GST_OBJECT_UNLOCK (oss); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstCaps * +gst_oss4_source_getcaps (GstBaseSrc * bsrc) +{ + GstOss4Source *oss; + GstCaps *caps; + + oss = GST_OSS4_SOURCE (bsrc); + + if (oss->fd == -1) { + caps = gst_oss4_audio_get_template_caps (); + } else if (oss->probed_caps) { + caps = gst_caps_copy (oss->probed_caps); + } else { + caps = gst_oss4_audio_probe_caps (GST_OBJECT (oss), oss->fd); + if (caps != NULL && !gst_caps_is_empty (caps)) { + oss->probed_caps = gst_caps_copy (caps); + } + } + + return caps; +} + +/* note: we must not take the object lock here unless we fix up get_property */ +static gboolean +gst_oss4_source_open (GstAudioSrc * asrc, gboolean silent_errors) +{ + GstOss4Source *oss; + gchar *device; + int mode; + + oss = GST_OSS4_SOURCE (asrc); + + if (oss->device) + device = g_strdup (oss->device); + else + device = gst_oss4_audio_find_device (GST_OBJECT_CAST (oss)); + + /* desperate times, desperate measures */ + if (device == NULL) + device = g_strdup ("/dev/dsp0"); + + GST_INFO_OBJECT (oss, "Trying to open OSS4 device '%s'", device); + + /* we open in non-blocking mode even if we don't really want to do writes + * non-blocking because we can't be sure that this is really a genuine + * OSS4 device with well-behaved drivers etc. We really don't want to + * hang forever under any circumstances. */ + oss->fd = open (device, O_RDONLY | O_NONBLOCK, 0); + if (oss->fd == -1) { + switch (errno) { + case EBUSY: + goto busy; + case EACCES: + goto no_permission; + default: + goto open_failed; + } + } + + GST_INFO_OBJECT (oss, "Opened device"); + + /* Make sure it's OSS4. If it's old OSS, let osssink handle it */ + if (!gst_oss4_audio_check_version (GST_OBJECT_CAST (oss), oss->fd)) + goto legacy_oss; + + /* now remove the non-blocking flag. */ + mode = fcntl (oss->fd, F_GETFL); + mode &= ~O_NONBLOCK; + if (fcntl (oss->fd, F_SETFL, mode) < 0) { + /* some drivers do no support unsetting the non-blocking flag, try to + * close/open the device then. This is racy but we error out properly. */ + GST_WARNING_OBJECT (oss, "failed to unset O_NONBLOCK (buggy driver?), " + "will try to re-open device now"); + gst_oss4_source_close (asrc); + if ((oss->fd = open (device, O_RDONLY, 0)) == -1) + goto non_block; + } + + oss->open_device = device; + + /* not using ENGINEINFO here because it sometimes returns a different and + * less useful name than AUDIOINFO for the same device */ + if (!gst_oss4_property_probe_find_device_name (GST_OBJECT (oss), oss->fd, + oss->open_device, &oss->device_name)) { + oss->device_name = NULL; + } + + return TRUE; + + /* ERRORS */ +busy: + { + if (!silent_errors) { + GST_ELEMENT_ERROR (oss, RESOURCE, BUSY, + (_("Could not open audio device for playback. " + "Device is being used by another application.")), (NULL)); + } + g_free (device); + return FALSE; + } +no_permission: + { + if (!silent_errors) { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ, + (_("Could not open audio device for playback. " + "You don't have permission to open the device.")), + GST_ERROR_SYSTEM); + } + g_free (device); + return FALSE; + } +open_failed: + { + if (!silent_errors) { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ, + (_("Could not open audio device for playback.")), GST_ERROR_SYSTEM); + } + g_free (device); + return FALSE; + } +legacy_oss: + { + gst_oss4_source_close (asrc); + if (!silent_errors) { + GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ, + (_("Could not open audio device for playback. " + "This version of the Open Sound System is not supported by this " + "element.")), ("Try the 'osssink' element instead")); + } + g_free (device); + return FALSE; + } +non_block: + { + if (!silent_errors) { + GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL), + ("Unable to set device %s into non-blocking mode: %s", + oss->device, g_strerror (errno))); + } + g_free (device); + return FALSE; + } +} + +static gboolean +gst_oss4_source_open_func (GstAudioSrc * asrc) +{ + return gst_oss4_source_open (asrc, FALSE); +} + +static void +gst_oss4_source_free_mixer_tracks (GstOss4Source * oss) +{ + g_list_foreach (oss->tracks, (GFunc) g_object_unref, NULL); + g_list_free (oss->tracks); + oss->tracks = NULL; +} + +static gboolean +gst_oss4_source_close (GstAudioSrc * asrc) +{ + GstOss4Source *oss; + + oss = GST_OSS4_SOURCE (asrc); + + if (oss->fd != -1) { + GST_DEBUG_OBJECT (oss, "closing device"); + close (oss->fd); + oss->fd = -1; + } + + oss->bytes_per_sample = 0; + + gst_caps_replace (&oss->probed_caps, NULL); + + g_free (oss->open_device); + oss->open_device = NULL; + + g_free (oss->device_name); + oss->device_name = NULL; + + gst_oss4_source_free_mixer_tracks (oss); + + return TRUE; +} + +static gboolean +gst_oss4_source_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec) +{ + GstOss4Source *oss; + + oss = GST_OSS4_SOURCE (asrc); + + if (!gst_oss4_audio_set_format (GST_OBJECT_CAST (oss), oss->fd, spec)) { + GST_WARNING_OBJECT (oss, "Couldn't set requested format %" GST_PTR_FORMAT, + spec->caps); + return FALSE; + } + + oss->bytes_per_sample = spec->bytes_per_sample; + return TRUE; +} + +static gboolean +gst_oss4_source_unprepare (GstAudioSrc * asrc) +{ + /* could do a SNDCTL_DSP_HALT, but the OSS manual recommends a close/open, + * since HALT won't properly reset some devices, apparently */ + + if (!gst_oss4_source_close (asrc)) + goto couldnt_close; + + if (!gst_oss4_source_open_func (asrc)) + goto couldnt_reopen; + + return TRUE; + + /* ERRORS */ +couldnt_close: + { + GST_DEBUG_OBJECT (asrc, "Couldn't close the audio device"); + return FALSE; + } +couldnt_reopen: + { + GST_DEBUG_OBJECT (asrc, "Couldn't reopen the audio device"); + return FALSE; + } +} + +static guint +gst_oss4_source_read (GstAudioSrc * asrc, gpointer data, guint length) +{ + GstOss4Source *oss; + int n; + + oss = GST_OSS4_SOURCE_CAST (asrc); + + n = read (oss->fd, data, length); + GST_LOG_OBJECT (asrc, "%u bytes, %u samples", n, n / oss->bytes_per_sample); + + if (G_UNLIKELY (n < 0)) { + switch (errno) { + case ENOTSUP: + case EACCES:{ + /* This is the most likely cause, I think */ + GST_ELEMENT_ERROR (asrc, RESOURCE, READ, + (_("Recording is not supported by this audio device.")), + ("read: %s (device: %s) (maybe this is an output-only device?)", + g_strerror (errno), oss->open_device)); + break; + } + default:{ + GST_ELEMENT_ERROR (asrc, RESOURCE, READ, + (_("Error recording from audio device.")), + ("read: %s (device: %s)", g_strerror (errno), oss->open_device)); + break; + } + } + } + + return (guint) n; +} + +static guint +gst_oss4_source_delay (GstAudioSrc * asrc) +{ + audio_buf_info info = { 0, }; + GstOss4Source *oss; + guint delay; + + oss = GST_OSS4_SOURCE_CAST (asrc); + + if (ioctl (oss->fd, SNDCTL_DSP_GETISPACE, &info) == -1) { + GST_LOG_OBJECT (oss, "GETISPACE failed: %s", g_strerror (errno)); + return 0; + } + + delay = (info.fragstotal * info.fragsize) - info.bytes; + GST_LOG_OBJECT (oss, "fragstotal:%d, fragsize:%d, bytes:%d, delay:%d", + info.fragstotal, info.fragsize, info.bytes, delay); + return delay; +} + +static void +gst_oss4_source_reset (GstAudioSrc * asrc) +{ + /* There's nothing we can do here really: OSS can't handle access to the + * same device/fd from multiple threads and might deadlock or blow up in + * other ways if we try an ioctl SNDCTL_DSP_HALT or similar */ +} + +/* GstMixer interface, which we abuse here for input selection, because we + * don't have a proper interface for that and because that's what + * gnome-sound-recorder does. */ + +/* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */ +G_DEFINE_TYPE (GstOss4SourceInput, gst_oss4_source_input, GST_TYPE_MIXER_TRACK); + +static void +gst_oss4_source_input_class_init (GstOss4SourceInputClass * klass) +{ + /* nothing to do here */ +} + +static void +gst_oss4_source_input_init (GstOss4SourceInput * i) +{ + /* nothing to do here */ +} + +#if 0 + +static void +gst_ossmixer_ensure_track_list (GstOssMixer * mixer) +{ + gint i, master = -1; + + g_return_if_fail (mixer->fd != -1); + + if (mixer->tracklist) + return; + + /* find master volume */ + if (mixer->devmask & SOUND_MASK_VOLUME) + master = SOUND_MIXER_VOLUME; + else if (mixer->devmask & SOUND_MASK_PCM) + master = SOUND_MIXER_PCM; + else if (mixer->devmask & SOUND_MASK_SPEAKER) + master = SOUND_MIXER_SPEAKER; /* doubtful... */ + /* else: no master, so we won't set any */ + + /* build track list */ + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (mixer->devmask & (1 << i)) { + GstMixerTrack *track; + gboolean input = FALSE, stereo = FALSE, record = FALSE; + + /* track exists, make up capabilities */ + if (MASK_BIT_IS_SET (mixer->stereomask, i)) + stereo = TRUE; + if (MASK_BIT_IS_SET (mixer->recmask, i)) + input = TRUE; + if (MASK_BIT_IS_SET (mixer->recdevs, i)) + record = TRUE; + + /* do we want mixer in our list? */ + if (!((mixer->dir & GST_OSS_MIXER_CAPTURE && input == TRUE) || + (mixer->dir & GST_OSS_MIXER_PLAYBACK && i != SOUND_MIXER_PCM))) + /* the PLAYBACK case seems hacky, but that's how 0.8 had it */ + continue; + + /* add track to list */ + track = gst_ossmixer_track_new (mixer->fd, i, stereo ? 2 : 1, + (record ? GST_MIXER_TRACK_RECORD : 0) | + (input ? GST_MIXER_TRACK_INPUT : + GST_MIXER_TRACK_OUTPUT) | + ((master != i) ? 0 : GST_MIXER_TRACK_MASTER)); + mixer->tracklist = g_list_append (mixer->tracklist, track); + } + } +} + +/* unused with G_DISABLE_* */ +static G_GNUC_UNUSED gboolean +gst_ossmixer_contains_track (GstOssMixer * mixer, GstOssMixerTrack * osstrack) +{ + const GList *item; + + for (item = mixer->tracklist; item != NULL; item = item->next) + if (item->data == osstrack) + return TRUE; + + return FALSE; +} + +const GList * +gst_ossmixer_list_tracks (GstOssMixer * mixer) +{ + gst_ossmixer_ensure_track_list (mixer); + + return (const GList *) mixer->tracklist; +} + +void +gst_ossmixer_get_volume (GstOssMixer * mixer, + GstMixerTrack * track, gint * volumes) +{ + gint volume; + GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track); + + g_return_if_fail (mixer->fd != -1); + g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack)); + + if (track->flags & GST_MIXER_TRACK_MUTE) { + volumes[0] = osstrack->lvol; + if (track->num_channels == 2) { + volumes[1] = osstrack->rvol; + } + } else { + /* get */ + if (ioctl (mixer->fd, MIXER_READ (osstrack->track_num), &volume) < 0) { + g_warning ("Error getting recording device (%d) volume: %s", + osstrack->track_num, g_strerror (errno)); + volume = 0; + } + + osstrack->lvol = volumes[0] = (volume & 0xff); + if (track->num_channels == 2) { + osstrack->rvol = volumes[1] = ((volume >> 8) & 0xff); + } + } +} + +void +gst_ossmixer_set_mute (GstOssMixer * mixer, GstMixerTrack * track, + gboolean mute) +{ + int volume; + GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track); + + g_return_if_fail (mixer->fd != -1); + g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack)); + + if (mute) { + volume = 0; + } else { + volume = (osstrack->lvol & 0xff); + if (MASK_BIT_IS_SET (mixer->stereomask, osstrack->track_num)) { + volume |= ((osstrack->rvol & 0xff) << 8); + } + } + + if (ioctl (mixer->fd, MIXER_WRITE (osstrack->track_num), &volume) < 0) { + g_warning ("Error setting mixer recording device volume (0x%x): %s", + volume, g_strerror (errno)); + return; + } + + if (mute) { + track->flags |= GST_MIXER_TRACK_MUTE; + } else { + track->flags &= ~GST_MIXER_TRACK_MUTE; + } +} +#endif + +static gint +gst_oss4_source_mixer_get_current_input (GstOss4Source * oss) +{ + int cur = -1; + + if (ioctl (oss->fd, SNDCTL_DSP_GET_RECSRC, &cur) == -1 || cur < 0) + return -1; + + return cur; +} + +static const gchar * +gst_oss4_source_mixer_update_record_flags (GstOss4Source * oss, gint cur_route) +{ + const gchar *cur_name = ""; + GList *t; + + for (t = oss->tracks; t != NULL; t = t->next) { + GstMixerTrack *track = t->data; + + if (GST_OSS4_SOURCE_INPUT (track)->route == cur_route) { + if (!GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD)) { + track->flags |= GST_MIXER_TRACK_RECORD; + /* no point in sending a mixer-record-changes message here */ + } + cur_name = track->label; + } else { + if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD)) { + track->flags &= ~GST_MIXER_TRACK_RECORD; + /* no point in sending a mixer-record-changes message here */ + } + } + } + + return cur_name; +} + +static const GList * +gst_oss4_source_mixer_list_tracks (GstMixer * mixer) +{ + oss_mixer_enuminfo names = { 0, }; + GstOss4Source *oss; + const gchar *cur_name; + GList *tracks = NULL; + gint i, cur; + + g_return_val_if_fail (mixer != NULL, NULL); + g_return_val_if_fail (GST_IS_OSS4_SOURCE (mixer), NULL); + g_return_val_if_fail (GST_OSS4_SOURCE_IS_OPEN (mixer), NULL); + + oss = GST_OSS4_SOURCE (mixer); + + if (oss->tracks != NULL && oss->tracks_static) + goto done; + + if (ioctl (oss->fd, SNDCTL_DSP_GET_RECSRC_NAMES, &names) == -1) + goto get_recsrc_names_error; + + oss->tracks_static = (names.version == 0); + + GST_INFO_OBJECT (oss, "%d inputs (list is static: %s):", names.nvalues, + (oss->tracks_static) ? "yes" : "no"); + + for (i = 0; i < MIN (names.nvalues, OSS_ENUM_MAXVALUE + 1); ++i) { + GstMixerTrack *track; + + track = g_object_new (GST_TYPE_OSS4_SOURCE_INPUT, NULL); + track->label = g_strdup (&names.strings[names.strindex[i]]); + track->flags = GST_MIXER_TRACK_INPUT; + track->num_channels = 2; + track->min_volume = 0; + track->max_volume = 100; + GST_OSS4_SOURCE_INPUT (track)->route = i; + + GST_INFO_OBJECT (oss, " [%d] %s", i, track->label); + tracks = g_list_append (tracks, track); + } + + gst_oss4_source_free_mixer_tracks (oss); + oss->tracks = tracks; + +done: + + /* update RECORD flags */ + cur = gst_oss4_source_mixer_get_current_input (oss); + cur_name = gst_oss4_source_mixer_update_record_flags (oss, cur); + GST_DEBUG_OBJECT (oss, "current input route: %d (%s)", cur, cur_name); + + return (const GList *) oss->tracks; + +/* ERRORS */ +get_recsrc_names_error: + { + GST_WARNING_OBJECT (oss, "GET_RECSRC_NAMES failed: %s", g_strerror (errno)); + return NULL; + } +} + +static void +gst_oss4_source_mixer_set_volume (GstMixer * mixer, GstMixerTrack * track, + gint * volumes) +{ + GstOss4Source *oss; + int new_vol, cur; + + g_return_if_fail (mixer != NULL); + g_return_if_fail (track != NULL); + g_return_if_fail (GST_IS_MIXER_TRACK (track)); + g_return_if_fail (GST_IS_OSS4_SOURCE (mixer)); + g_return_if_fail (GST_OSS4_SOURCE_IS_OPEN (mixer)); + + oss = GST_OSS4_SOURCE (mixer); + + cur = gst_oss4_source_mixer_get_current_input (oss); + if (cur != GST_OSS4_SOURCE_INPUT (track)->route) { + GST_DEBUG_OBJECT (oss, "track not selected input route, ignoring request"); + return; + } + + new_vol = (volumes[1] << 8) | volumes[0]; + if (ioctl (oss->fd, SNDCTL_DSP_SETRECVOL, &new_vol) == -1) { + GST_WARNING_OBJECT (oss, "SETRECVOL failed: %s", g_strerror (errno)); + } +} + +static void +gst_oss4_source_mixer_get_volume (GstMixer * mixer, GstMixerTrack * track, + gint * volumes) +{ + GstOss4Source *oss; + int cur; + + g_return_if_fail (mixer != NULL); + g_return_if_fail (GST_IS_OSS4_SOURCE (mixer)); + g_return_if_fail (GST_OSS4_SOURCE_IS_OPEN (mixer)); + + oss = GST_OSS4_SOURCE (mixer); + + cur = gst_oss4_source_mixer_get_current_input (oss); + if (cur != GST_OSS4_SOURCE_INPUT (track)->route) { + volumes[0] = 0; + volumes[1] = 0; + } else { + int vol = -1; + + if (ioctl (oss->fd, SNDCTL_DSP_GETRECVOL, &vol) == -1 || vol < 0) { + GST_WARNING_OBJECT (oss, "GETRECVOL failed: %s", g_strerror (errno)); + volumes[0] = 100; + volumes[1] = 100; + } else { + volumes[0] = MIN (100, vol & 0xff); + volumes[1] = MIN (100, (vol >> 8) & 0xff); + } + } +} + +static void +gst_oss4_source_mixer_set_record (GstMixer * mixer, GstMixerTrack * track, + gboolean record) +{ + GstOss4Source *oss; + const gchar *cur_name; + gint cur; + + g_return_if_fail (mixer != NULL); + g_return_if_fail (track != NULL); + g_return_if_fail (GST_IS_MIXER_TRACK (track)); + g_return_if_fail (GST_IS_OSS4_SOURCE (mixer)); + g_return_if_fail (GST_OSS4_SOURCE_IS_OPEN (mixer)); + + oss = GST_OSS4_SOURCE (mixer); + + cur = gst_oss4_source_mixer_get_current_input (oss); + + /* stop recording for an input that's not selected anyway => nothing to do */ + if (!record && cur != GST_OSS4_SOURCE_INPUT (track)->route) + goto done; + + /* select recording for an input that's already selected => nothing to do + * (or should we mess with the recording volume in this case maybe?) */ + if (record && cur == GST_OSS4_SOURCE_INPUT (track)->route) + goto done; + + /* make current input stop recording: we can't really make an input stop + * recording, we can only select an input FOR recording, so we'll just ignore + * all requests to stop for now */ + if (!record) { + GST_WARNING_OBJECT (oss, "Can't un-select an input as such, only switch " + "to a different input source"); + /* FIXME: set recording volume to 0 maybe? */ + } else { + int new_route = GST_OSS4_SOURCE_INPUT (track)->route; + + /* select this input for recording */ + + if (ioctl (oss->fd, SNDCTL_DSP_SET_RECSRC, &new_route) == -1) { + GST_WARNING_OBJECT (oss, "Could not select input %d for recording: %s", + new_route, g_strerror (errno)); + } else { + cur = new_route; + } + } + +done: + + cur_name = gst_oss4_source_mixer_update_record_flags (oss, cur); + GST_DEBUG_OBJECT (oss, "active input route: %d (%s)", cur, cur_name); +} + +static void +gst_oss4_source_mixer_set_mute (GstMixer * mixer, GstMixerTrack * track, + gboolean mute) +{ + g_return_if_fail (mixer != NULL); + g_return_if_fail (track != NULL); + g_return_if_fail (GST_IS_MIXER_TRACK (track)); + g_return_if_fail (GST_IS_OSS4_SOURCE (mixer)); + g_return_if_fail (GST_OSS4_SOURCE_IS_OPEN (mixer)); + + /* FIXME: implement gst_oss4_source_mixer_set_mute() - what to do here? */ + /* oss4_mixer_set_mute (mixer->mixer, track, mute); */ +} + +static void +gst_oss4_source_mixer_interface_init (GstMixerClass * klass) +{ + GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; + + klass->list_tracks = gst_oss4_source_mixer_list_tracks; + klass->set_volume = gst_oss4_source_mixer_set_volume; + klass->get_volume = gst_oss4_source_mixer_get_volume; + klass->set_mute = gst_oss4_source_mixer_set_mute; + klass->set_record = gst_oss4_source_mixer_set_record; +} + +/* Implement the horror that is GstImplementsInterface */ + +static gboolean +gst_oss4_source_mixer_supported (GstImplementsInterface * iface, + GType iface_type) +{ + GstOss4Source *oss; + gboolean is_open; + + g_return_val_if_fail (GST_IS_OSS4_SOURCE (iface), FALSE); + g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE); + + oss = GST_OSS4_SOURCE (iface); + + GST_OBJECT_LOCK (oss); + is_open = GST_OSS4_SOURCE_IS_OPEN (iface); + GST_OBJECT_UNLOCK (oss); + + return is_open; +} + +static void +gst_oss4_source_mixer_implements_interface_init (GstImplementsInterfaceClass * + klass) +{ + klass->supported = gst_oss4_source_mixer_supported; +} + +static void +gst_oss4_source_init_interfaces (GType type) +{ + static const GInterfaceInfo implements_iface_info = { + (GInterfaceInitFunc) gst_oss4_source_mixer_implements_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo mixer_iface_info = { + (GInterfaceInitFunc) gst_oss4_source_mixer_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); + + gst_oss4_add_property_probe_interface (type); +} diff --git a/sys/oss4/oss4-source.h b/sys/oss4/oss4-source.h new file mode 100644 index 0000000..3a86b43 --- /dev/null +++ b/sys/oss4/oss4-source.h @@ -0,0 +1,89 @@ +/* GStreamer OSS4 audio source + * Copyright (C) 2007-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_OSS4_SOURCE_H +#define GST_OSS4_SOURCE_H + +#include <gst/gst.h> +#include <gst/audio/gstaudiosrc.h> +#include <gst/interfaces/mixertrack.h> + +G_BEGIN_DECLS + +#define GST_TYPE_OSS4_SOURCE (gst_oss4_source_get_type()) +#define GST_OSS4_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_SOURCE,GstOss4Source)) +#define GST_OSS4_SOURCE_CAST(obj) ((GstOss4Source *)(obj)) +#define GST_OSS4_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_SOURCE,GstOss4SourceClass)) +#define GST_IS_OSS4_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_SOURCE)) +#define GST_IS_OSS4_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_SOURCE)) + +typedef struct _GstOss4Source GstOss4Source; +typedef struct _GstOss4SourceClass GstOss4SourceClass; + +struct _GstOss4Source { + GstAudioSrc audiosrc; + + gchar * device; /* NULL if none was set */ + gchar * open_device; /* the device we opened */ + gchar * device_name; /* set if the device is open */ + gint fd; /* -1 if not open */ + gint bytes_per_sample; + + GstCaps * probed_caps; + + /* property probe interface */ + GList * property_probe_list; + + /* mixer interface */ + GList * tracks; + gboolean tracks_static; /* FALSE if the list of inputs may change */ +}; + +struct _GstOss4SourceClass { + GstAudioSrcClass audiosrc_class; +}; + +GType gst_oss4_source_get_type (void); + +/* our mixer track for input selection */ +#define GST_TYPE_OSS4_SOURCE_INPUT (gst_oss4_source_input_get_type()) +#define GST_OSS4_SOURCE_INPUT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS4_SOURCE_INPUT,GstOss4SourceInput)) +#define GST_OSS4_SOURCE_INPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS4_SOURCE_INPUT,GstOss4SourceInputClass)) +#define GST_IS_OSS4_SOURCE_INPUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS4_SOURCE_INPUT)) +#define GST_IS_OSS4_SOURCE_INPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS4_SOURCE_INPUT)) + +typedef struct _GstOss4SourceInput GstOss4SourceInput; +typedef struct _GstOss4SourceInputClass GstOss4SourceInputClass; + +struct _GstOss4SourceInput { + GstMixerTrack mixer_track; + + int route; /* number for SNDCTL_DSP_SET_RECSRC etc. */ +}; + +struct _GstOss4SourceInputClass { + GstMixerTrackClass mixer_track_class; +}; + +GType gst_oss4_source_input_get_type (void); + +G_END_DECLS + +#endif /* GST_OSS4_SOURCE_H */ + diff --git a/sys/osxaudio/Makefile.am b/sys/osxaudio/Makefile.am new file mode 100644 index 0000000..cfd0c4d --- /dev/null +++ b/sys/osxaudio/Makefile.am @@ -0,0 +1,26 @@ +plugin_LTLIBRARIES = libgstosxaudio.la + +libgstosxaudio_la_SOURCES = gstosxringbuffer.c \ + gstosxaudioelement.c \ + gstosxaudiosink.c \ + gstosxaudiosrc.c \ + gstosxaudio.c + +libgstosxaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \ + -Wno-deprecated-declarations +libgstosxaudio_la_LIBADD = \ + -lgstinterfaces-@GST_MAJORMINOR@ \ + -lgstaudio-@GST_MAJORMINOR@ \ + $(GST_PLUGINS_BASE_LIBS) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) +libgstosxaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -Wl,-framework -Wl,CoreAudio -Wl,-framework -Wl,AudioUnit -Wl,-framework -Wl,CoreServices +libgstosxaudio_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstosxaudiosink.h \ + gstosxaudioelement.h \ + gstosxringbuffer.h \ + gstosxaudiosrc.h + + + diff --git a/sys/osxaudio/Makefile.in b/sys/osxaudio/Makefile.in new file mode 100644 index 0000000..9e8e186 --- /dev/null +++ b/sys/osxaudio/Makefile.in @@ -0,0 +1,858 @@ +# 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 = sys/osxaudio +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 = +libgstosxaudio_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgstosxaudio_la_OBJECTS = libgstosxaudio_la-gstosxringbuffer.lo \ + libgstosxaudio_la-gstosxaudioelement.lo \ + libgstosxaudio_la-gstosxaudiosink.lo \ + libgstosxaudio_la-gstosxaudiosrc.lo \ + libgstosxaudio_la-gstosxaudio.lo +libgstosxaudio_la_OBJECTS = $(am_libgstosxaudio_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +libgstosxaudio_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) \ + $(libgstosxaudio_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 = $(libgstosxaudio_la_SOURCES) +DIST_SOURCES = $(libgstosxaudio_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 = libgstosxaudio.la +libgstosxaudio_la_SOURCES = gstosxringbuffer.c \ + gstosxaudioelement.c \ + gstosxaudiosink.c \ + gstosxaudiosrc.c \ + gstosxaudio.c + +libgstosxaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \ + -Wno-deprecated-declarations + +libgstosxaudio_la_LIBADD = \ + -lgstinterfaces-@GST_MAJORMINOR@ \ + -lgstaudio-@GST_MAJORMINOR@ \ + $(GST_PLUGINS_BASE_LIBS) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) + +libgstosxaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -Wl,-framework -Wl,CoreAudio -Wl,-framework -Wl,AudioUnit -Wl,-framework -Wl,CoreServices +libgstosxaudio_la_LIBTOOLFLAGS = --tag=disable-static +noinst_HEADERS = gstosxaudiosink.h \ + gstosxaudioelement.h \ + gstosxringbuffer.h \ + gstosxaudiosrc.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 sys/osxaudio/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu sys/osxaudio/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 +libgstosxaudio.la: $(libgstosxaudio_la_OBJECTS) $(libgstosxaudio_la_DEPENDENCIES) $(EXTRA_libgstosxaudio_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgstosxaudio_la_LINK) -rpath $(plugindir) $(libgstosxaudio_la_OBJECTS) $(libgstosxaudio_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxaudio_la-gstosxaudio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxaudio_la-gstosxaudioelement.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxaudio_la-gstosxaudiosink.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxaudio_la-gstosxaudiosrc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxaudio_la-gstosxringbuffer.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 $@ $< + +libgstosxaudio_la-gstosxringbuffer.lo: gstosxringbuffer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -MT libgstosxaudio_la-gstosxringbuffer.lo -MD -MP -MF $(DEPDIR)/libgstosxaudio_la-gstosxringbuffer.Tpo -c -o libgstosxaudio_la-gstosxringbuffer.lo `test -f 'gstosxringbuffer.c' || echo '$(srcdir)/'`gstosxringbuffer.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxaudio_la-gstosxringbuffer.Tpo $(DEPDIR)/libgstosxaudio_la-gstosxringbuffer.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosxringbuffer.c' object='libgstosxaudio_la-gstosxringbuffer.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 $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -c -o libgstosxaudio_la-gstosxringbuffer.lo `test -f 'gstosxringbuffer.c' || echo '$(srcdir)/'`gstosxringbuffer.c + +libgstosxaudio_la-gstosxaudioelement.lo: gstosxaudioelement.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -MT libgstosxaudio_la-gstosxaudioelement.lo -MD -MP -MF $(DEPDIR)/libgstosxaudio_la-gstosxaudioelement.Tpo -c -o libgstosxaudio_la-gstosxaudioelement.lo `test -f 'gstosxaudioelement.c' || echo '$(srcdir)/'`gstosxaudioelement.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxaudio_la-gstosxaudioelement.Tpo $(DEPDIR)/libgstosxaudio_la-gstosxaudioelement.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosxaudioelement.c' object='libgstosxaudio_la-gstosxaudioelement.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 $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -c -o libgstosxaudio_la-gstosxaudioelement.lo `test -f 'gstosxaudioelement.c' || echo '$(srcdir)/'`gstosxaudioelement.c + +libgstosxaudio_la-gstosxaudiosink.lo: gstosxaudiosink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -MT libgstosxaudio_la-gstosxaudiosink.lo -MD -MP -MF $(DEPDIR)/libgstosxaudio_la-gstosxaudiosink.Tpo -c -o libgstosxaudio_la-gstosxaudiosink.lo `test -f 'gstosxaudiosink.c' || echo '$(srcdir)/'`gstosxaudiosink.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxaudio_la-gstosxaudiosink.Tpo $(DEPDIR)/libgstosxaudio_la-gstosxaudiosink.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosxaudiosink.c' object='libgstosxaudio_la-gstosxaudiosink.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 $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -c -o libgstosxaudio_la-gstosxaudiosink.lo `test -f 'gstosxaudiosink.c' || echo '$(srcdir)/'`gstosxaudiosink.c + +libgstosxaudio_la-gstosxaudiosrc.lo: gstosxaudiosrc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -MT libgstosxaudio_la-gstosxaudiosrc.lo -MD -MP -MF $(DEPDIR)/libgstosxaudio_la-gstosxaudiosrc.Tpo -c -o libgstosxaudio_la-gstosxaudiosrc.lo `test -f 'gstosxaudiosrc.c' || echo '$(srcdir)/'`gstosxaudiosrc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxaudio_la-gstosxaudiosrc.Tpo $(DEPDIR)/libgstosxaudio_la-gstosxaudiosrc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosxaudiosrc.c' object='libgstosxaudio_la-gstosxaudiosrc.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 $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -c -o libgstosxaudio_la-gstosxaudiosrc.lo `test -f 'gstosxaudiosrc.c' || echo '$(srcdir)/'`gstosxaudiosrc.c + +libgstosxaudio_la-gstosxaudio.lo: gstosxaudio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -MT libgstosxaudio_la-gstosxaudio.lo -MD -MP -MF $(DEPDIR)/libgstosxaudio_la-gstosxaudio.Tpo -c -o libgstosxaudio_la-gstosxaudio.lo `test -f 'gstosxaudio.c' || echo '$(srcdir)/'`gstosxaudio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxaudio_la-gstosxaudio.Tpo $(DEPDIR)/libgstosxaudio_la-gstosxaudio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosxaudio.c' object='libgstosxaudio_la-gstosxaudio.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 $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -c -o libgstosxaudio_la-gstosxaudio.lo `test -f 'gstosxaudio.c' || echo '$(srcdir)/'`gstosxaudio.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/sys/osxaudio/gstosxaudio.c b/sys/osxaudio/gstosxaudio.c new file mode 100644 index 0000000..1ddfce4 --- /dev/null +++ b/sys/osxaudio/gstosxaudio.c @@ -0,0 +1,53 @@ +/* + * GStreamer + * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu> + * Copyright (C) 2007,2008 Pioneers of the Inevitable <songbird@songbirdnest.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. + * + * The development of this code was made possible due to the involvement of + * Pioneers of the Inevitable, the creators of the Songbird Music player + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstosxaudioelement.h" +#include "gstosxaudiosink.h" +#include "gstosxaudiosrc.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "osxaudiosink", GST_RANK_PRIMARY, + GST_TYPE_OSX_AUDIO_SINK)) { + return FALSE; + } + if (!gst_element_register (plugin, "osxaudiosrc", GST_RANK_PRIMARY, + GST_TYPE_OSX_AUDIO_SRC)) { + return FALSE; + } + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "osxaudio", + "OSX (Mac OS X) audio support for GStreamer", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/osxaudio/gstosxaudioelement.c b/sys/osxaudio/gstosxaudioelement.c new file mode 100644 index 0000000..a41f4b8 --- /dev/null +++ b/sys/osxaudio/gstosxaudioelement.c @@ -0,0 +1,92 @@ +/* + * GStreamer + * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com> + * + * 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. + * + * The development of this code was made possible due to the involvement of + * Pioneers of the Inevitable, the creators of the Songbird Music player + * + */ + +#include <gst/gst.h> +#include "gstosxaudioelement.h" + +static void +gst_osx_audio_element_class_init (GstOsxAudioElementInterface * klass); + +GType +gst_osx_audio_element_get_type (void) +{ + static GType gst_osxaudioelement_type = 0; + + if (!gst_osxaudioelement_type) { + static const GTypeInfo gst_osxaudioelement_info = { + sizeof (GstOsxAudioElementInterface), + (GBaseInitFunc) gst_osx_audio_element_class_init, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL, + NULL + }; + + gst_osxaudioelement_type = g_type_register_static (G_TYPE_INTERFACE, + "GstOsxAudioElement", &gst_osxaudioelement_info, 0); + } + + return gst_osxaudioelement_type; +} + +static void +gst_osx_audio_element_class_init (GstOsxAudioElementInterface * klass) +{ + static gboolean initialized = FALSE; + + if (!initialized) { + initialized = TRUE; + } + + /* default virtual functions */ + klass->io_proc = NULL; +} diff --git a/sys/osxaudio/gstosxaudioelement.h b/sys/osxaudio/gstosxaudioelement.h new file mode 100644 index 0000000..b5d90c0 --- /dev/null +++ b/sys/osxaudio/gstosxaudioelement.h @@ -0,0 +1,84 @@ +/* + * GStreamer + * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com> + * + * 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. + * + * The development of this code was made possible due to the involvement of + * Pioneers of the Inevitable, the creators of the Songbird Music player + * + */ + +#ifndef __GST_OSX_AUDIO_ELEMENT_H__ +#define __GST_OSX_AUDIO_ELEMENT_H__ + +#include <gst/gst.h> +#include <CoreAudio/CoreAudio.h> +#include <AudioUnit/AudioUnit.h> + +G_BEGIN_DECLS + +#define GST_OSX_AUDIO_ELEMENT_TYPE \ + (gst_osx_audio_element_get_type()) +#define GST_OSX_AUDIO_ELEMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_OSX_AUDIO_ELEMENT_TYPE,GstOsxAudioElementInterface)) +#define GST_IS_OSX_AUDIO_ELEMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_OSX_AUDIO_ELEMENT_TYPE)) +#define GST_OSX_AUDIO_ELEMENT_GET_INTERFACE(inst) \ + (G_TYPE_INSTANCE_GET_INTERFACE((inst),GST_OSX_AUDIO_ELEMENT_TYPE,GstOsxAudioElementInterface)) + +typedef struct _GstOsxAudioElementInterface GstOsxAudioElementInterface; + +struct _GstOsxAudioElementInterface +{ + GTypeInterface parent; + + OSStatus (*io_proc) (void * userdata, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList * bufferList); +}; + +GType gst_osx_audio_element_get_type (void); + +G_END_DECLS + +#endif /* __GST_OSX_AUDIO_ELEMENT_H__ */ diff --git a/sys/osxaudio/gstosxaudiosink.c b/sys/osxaudio/gstosxaudiosink.c new file mode 100644 index 0000000..cd456e5 --- /dev/null +++ b/sys/osxaudio/gstosxaudiosink.c @@ -0,0 +1,348 @@ +/* + * GStreamer + * Copyright (C) 2005,2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2007,2008 Pioneers of the Inevitable <songbird@songbirdnest.com> + * + * 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. + * + * The development of this code was made possible due to the involvement of + * Pioneers of the Inevitable, the creators of the Songbird Music player + * + */ + +/** + * SECTION:element-osxaudiosink + * + * This element renders raw audio samples using the CoreAudio api. + * + * <refsect2> + * <title>Example pipelines</title> + * |[ + * gst-launch filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! osxaudiosink + * ]| Play an Ogg/Vorbis file. + * </refsect2> + * + * Last reviewed on 2006-03-01 (0.10.4) + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gst/gst.h> +#include <CoreAudio/CoreAudio.h> +#include <CoreAudio/AudioHardware.h> +#include "gstosxaudiosink.h" +#include "gstosxaudioelement.h" + +GST_DEBUG_CATEGORY_STATIC (osx_audiosink_debug); +#define GST_CAT_DEFAULT osx_audiosink_debug + +/* Filter signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0, + ARG_DEVICE, + ARG_VOLUME +}; + +#define DEFAULT_VOLUME 1.0 + +static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-float, " + "endianness = (int) {" G_STRINGIFY (G_BYTE_ORDER) " }, " + "signed = (boolean) { TRUE }, " + "width = (int) 32, " + "depth = (int) 32, " + "rate = (int) [1, MAX], " "channels = (int) [1, MAX]") + ); + +static void gst_osx_audio_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_osx_audio_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstRingBuffer *gst_osx_audio_sink_create_ringbuffer (GstBaseAudioSink * + sink); +static void gst_osx_audio_sink_osxelement_init (gpointer g_iface, + gpointer iface_data); +static void gst_osx_audio_sink_select_device (GstOsxAudioSink * osxsink); +static void gst_osx_audio_sink_set_volume (GstOsxAudioSink * sink); + +static OSStatus gst_osx_audio_sink_io_proc (GstOsxRingBuffer * buf, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * bufferList); + +static void +gst_osx_audio_sink_do_init (GType type) +{ + static const GInterfaceInfo osxelement_info = { + gst_osx_audio_sink_osxelement_init, + NULL, + NULL + }; + + GST_DEBUG_CATEGORY_INIT (osx_audiosink_debug, "osxaudiosink", 0, + "OSX Audio Sink"); + GST_DEBUG ("Adding static interface"); + g_type_add_interface_static (type, GST_OSX_AUDIO_ELEMENT_TYPE, + &osxelement_info); +} + +GST_BOILERPLATE_FULL (GstOsxAudioSink, gst_osx_audio_sink, GstBaseAudioSink, + GST_TYPE_BASE_AUDIO_SINK, gst_osx_audio_sink_do_init); + +static void +gst_osx_audio_sink_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, "Audio Sink (OSX)", + "Sink/Audio", + "Output to a sound card in OS X", + "Zaheer Abbas Merali <zaheerabbas at merali dot org>"); +} + +static void +gst_osx_audio_sink_class_init (GstOsxAudioSinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *gstbasesink_class; + GstBaseAudioSinkClass *gstbaseaudiosink_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesink_class = (GstBaseSinkClass *) klass; + gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->set_property = gst_osx_audio_sink_set_property; + gobject_class->get_property = gst_osx_audio_sink_get_property; + + g_object_class_install_property (gobject_class, ARG_DEVICE, + g_param_spec_int ("device", "Device ID", "Device ID of output device", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, ARG_VOLUME, + g_param_spec_double ("volume", "Volume", "Volume of this stream", + 0, 1.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gstbaseaudiosink_class->create_ringbuffer = + GST_DEBUG_FUNCPTR (gst_osx_audio_sink_create_ringbuffer); +} + +static void +gst_osx_audio_sink_init (GstOsxAudioSink * sink, GstOsxAudioSinkClass * gclass) +{ + GST_DEBUG ("Initialising object"); + + sink->device_id = kAudioDeviceUnknown; + sink->volume = DEFAULT_VOLUME; +} + +static void +gst_osx_audio_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (object); + + switch (prop_id) { + case ARG_DEVICE: + sink->device_id = g_value_get_int (value); + break; + case ARG_VOLUME: + sink->volume = g_value_get_double (value); + gst_osx_audio_sink_set_volume (sink); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_osx_audio_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (object); + switch (prop_id) { + case ARG_DEVICE: + g_value_set_int (value, sink->device_id); + break; + case ARG_VOLUME: + g_value_set_double (value, sink->volume); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstRingBuffer * +gst_osx_audio_sink_create_ringbuffer (GstBaseAudioSink * sink) +{ + GstOsxAudioSink *osxsink; + GstOsxRingBuffer *ringbuffer; + + osxsink = GST_OSX_AUDIO_SINK (sink); + + gst_osx_audio_sink_select_device (osxsink); + + GST_DEBUG ("Creating ringbuffer"); + ringbuffer = g_object_new (GST_TYPE_OSX_RING_BUFFER, NULL); + GST_DEBUG ("osx sink 0x%p element 0x%p ioproc 0x%p", osxsink, + GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink), + (void *) gst_osx_audio_sink_io_proc); + + gst_osx_audio_sink_set_volume (osxsink); + + ringbuffer->element = GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink); + ringbuffer->device_id = osxsink->device_id; + + return GST_RING_BUFFER (ringbuffer); +} + +/* HALOutput AudioUnit will request fairly arbitrarily-sized chunks of data, + * not of a fixed size. So, we keep track of where in the current ringbuffer + * segment we are, and only advance the segment once we've read the whole + * thing */ +static OSStatus +gst_osx_audio_sink_io_proc (GstOsxRingBuffer * buf, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * bufferList) +{ + guint8 *readptr; + gint readseg; + gint len; + gint remaining = bufferList->mBuffers[0].mDataByteSize; + gint offset = 0; + + while (remaining) { + if (!gst_ring_buffer_prepare_read (GST_RING_BUFFER (buf), + &readseg, &readptr, &len)) + return 0; + + len -= buf->segoffset; + + if (len > remaining) + len = remaining; + + memcpy ((char *) bufferList->mBuffers[0].mData + offset, + readptr + buf->segoffset, len); + + buf->segoffset += len; + offset += len; + remaining -= len; + + if ((gint) buf->segoffset == GST_RING_BUFFER (buf)->spec.segsize) { + /* clear written samples */ + gst_ring_buffer_clear (GST_RING_BUFFER (buf), readseg); + + /* we wrote one segment */ + gst_ring_buffer_advance (GST_RING_BUFFER (buf), 1); + + buf->segoffset = 0; + } + } + return 0; +} + +static void +gst_osx_audio_sink_osxelement_init (gpointer g_iface, gpointer iface_data) +{ + GstOsxAudioElementInterface *iface = (GstOsxAudioElementInterface *) g_iface; + + iface->io_proc = (AURenderCallback) gst_osx_audio_sink_io_proc; +} + +static void +gst_osx_audio_sink_set_volume (GstOsxAudioSink * sink) +{ + if (!sink->audiounit) + return; + + AudioUnitSetParameter (sink->audiounit, kHALOutputParam_Volume, + kAudioUnitScope_Global, 0, (float) sink->volume, 0); +} + +static void +gst_osx_audio_sink_select_device (GstOsxAudioSink * osxsink) +{ + OSStatus status; + UInt32 propertySize; + + if (osxsink->device_id == kAudioDeviceUnknown) { + /* If no specific device has been selected by the user, then pick the + * default device */ + GST_DEBUG_OBJECT (osxsink, "Selecting device for OSXAudioSink"); + propertySize = sizeof (osxsink->device_id); + status = + AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice, + &propertySize, &osxsink->device_id); + + if (status) { + GST_WARNING_OBJECT (osxsink, + "AudioHardwareGetProperty returned %d", (int) status); + } else { + GST_DEBUG_OBJECT (osxsink, "AudioHardwareGetProperty returned 0"); + } + + if (osxsink->device_id == kAudioDeviceUnknown) { + GST_WARNING_OBJECT (osxsink, + "AudioHardwareGetProperty: device_id is kAudioDeviceUnknown"); + } + + GST_DEBUG_OBJECT (osxsink, "AudioHardwareGetProperty: device_id is %lu", + (long) osxsink->device_id); + } +} diff --git a/sys/osxaudio/gstosxaudiosink.h b/sys/osxaudio/gstosxaudiosink.h new file mode 100644 index 0000000..aac9719 --- /dev/null +++ b/sys/osxaudio/gstosxaudiosink.h @@ -0,0 +1,86 @@ +/* + * GStreamer + * Copyright (C) 2005-2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com> + * + * 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. + * + * The development of this code was made possible due to the involvement of + * Pioneers of the Inevitable, the creators of the Songbird Music player + * + */ + +#ifndef __GST_OSXAUDIOSINK_H__ +#define __GST_OSXAUDIOSINK_H__ + +#include <gst/gst.h> +#include <gst/audio/gstbaseaudiosink.h> +#include "gstosxringbuffer.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OSX_AUDIO_SINK \ + (gst_osx_audio_sink_get_type()) +#define GST_OSX_AUDIO_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSX_AUDIO_SINK,GstOsxAudioSink)) +#define GST_OSX_AUDIO_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_AUDIO_SINK,GstOsxAudioSinkClass)) + +typedef struct _GstOsxAudioSink GstOsxAudioSink; +typedef struct _GstOsxAudioSinkClass GstOsxAudioSinkClass; + +struct _GstOsxAudioSink +{ + GstBaseAudioSink sink; + + AudioDeviceID device_id; + AudioUnit audiounit; + double volume; +}; + +struct _GstOsxAudioSinkClass +{ + GstBaseAudioSinkClass parent_class; +}; + +GType gst_osx_audio_sink_get_type (void); + +G_END_DECLS + +#endif /* __GST_OSXAUDIOSINK_H__ */ diff --git a/sys/osxaudio/gstosxaudiosrc.c b/sys/osxaudio/gstosxaudiosrc.c new file mode 100644 index 0000000..7e9ad24 --- /dev/null +++ b/sys/osxaudio/gstosxaudiosrc.c @@ -0,0 +1,362 @@ +/* + * GStreamer + * Copyright (C) 2005,2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2008 Pioneers of the Inevitable <songbird@songbirdnest.com> + * + * 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-osxaudiosrc + * + * This element captures raw audio samples using the CoreAudio api. + * + * <refsect2> + * <title>Example launch line</title> + * |[ + * gst-launch osxaudiosrc ! wavenc ! filesink location=audio.wav + * ]| + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gst/gst.h> +#include <CoreAudio/CoreAudio.h> +#include <CoreAudio/AudioHardware.h> +#include "gstosxaudiosrc.h" +#include "gstosxaudioelement.h" + +GST_DEBUG_CATEGORY_STATIC (osx_audiosrc_debug); +#define GST_CAT_DEFAULT osx_audiosrc_debug + +/* Filter signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0, + ARG_DEVICE +}; + +static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-float, " + "endianness = (int) {" G_STRINGIFY (G_BYTE_ORDER) " }, " + "signed = (boolean) { TRUE }, " + "width = (int) 32, " + "depth = (int) 32, " + "rate = (int) [1, MAX], " "channels = (int) [1, MAX]") + ); + +static void gst_osx_audio_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_osx_audio_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstCaps *gst_osx_audio_src_get_caps (GstBaseSrc * src); + +static GstRingBuffer *gst_osx_audio_src_create_ringbuffer (GstBaseAudioSrc * + src); +static void gst_osx_audio_src_osxelement_init (gpointer g_iface, + gpointer iface_data); +static OSStatus gst_osx_audio_src_io_proc (GstOsxRingBuffer * buf, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber, + UInt32 inNumberFrames, AudioBufferList * bufferList); +static void gst_osx_audio_src_select_device (GstOsxAudioSrc * osxsrc); + +static void +gst_osx_audio_src_do_init (GType type) +{ + static const GInterfaceInfo osxelement_info = { + gst_osx_audio_src_osxelement_init, + NULL, + NULL + }; + + GST_DEBUG_CATEGORY_INIT (osx_audiosrc_debug, "osxaudiosrc", 0, + "OSX Audio Src"); + GST_DEBUG ("Adding static interface"); + g_type_add_interface_static (type, GST_OSX_AUDIO_ELEMENT_TYPE, + &osxelement_info); +} + +GST_BOILERPLATE_FULL (GstOsxAudioSrc, gst_osx_audio_src, GstBaseAudioSrc, + GST_TYPE_BASE_AUDIO_SRC, gst_osx_audio_src_do_init); + +static void +gst_osx_audio_src_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, "Audio Source (OSX)", + "Source/Audio", + "Input from a sound card in OS X", + "Zaheer Abbas Merali <zaheerabbas at merali dot org>"); +} + +static void +gst_osx_audio_src_class_init (GstOsxAudioSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSrcClass *gstbasesrc_class; + GstBaseAudioSrcClass *gstbaseaudiosrc_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesrc_class = (GstBaseSrcClass *) klass; + gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->set_property = gst_osx_audio_src_set_property; + gobject_class->get_property = gst_osx_audio_src_get_property; + + gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_osx_audio_src_get_caps); + + g_object_class_install_property (gobject_class, ARG_DEVICE, + g_param_spec_int ("device", "Device ID", "Device ID of input device", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gstbaseaudiosrc_class->create_ringbuffer = + GST_DEBUG_FUNCPTR (gst_osx_audio_src_create_ringbuffer); +} + +static void +gst_osx_audio_src_init (GstOsxAudioSrc * src, GstOsxAudioSrcClass * gclass) +{ + gst_base_src_set_live (GST_BASE_SRC (src), TRUE); + + src->device_id = kAudioDeviceUnknown; + src->deviceChannels = -1; +} + +static void +gst_osx_audio_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOsxAudioSrc *src = GST_OSX_AUDIO_SRC (object); + + switch (prop_id) { + case ARG_DEVICE: + src->device_id = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_osx_audio_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstOsxAudioSrc *src = GST_OSX_AUDIO_SRC (object); + + switch (prop_id) { + case ARG_DEVICE: + g_value_set_int (value, src->device_id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstCaps * +gst_osx_audio_src_get_caps (GstBaseSrc * src) +{ + GstElementClass *gstelement_class; + GstOsxAudioSrc *osxsrc; + GstPadTemplate *pad_template; + GstCaps *caps; + gint min, max; + + gstelement_class = GST_ELEMENT_GET_CLASS (src); + osxsrc = GST_OSX_AUDIO_SRC (src); + + if (osxsrc->deviceChannels == -1) { + /* -1 means we don't know the number of channels yet. for now, return + * template caps. + */ + return NULL; + } + + max = osxsrc->deviceChannels; + if (max < 1) + max = 1; /* 0 channels means 1 channel? */ + + min = MIN (1, max); + + pad_template = gst_element_class_get_pad_template (gstelement_class, "src"); + g_return_val_if_fail (pad_template != NULL, NULL); + + caps = gst_caps_copy (gst_pad_template_get_caps (pad_template)); + + if (min == max) { + gst_caps_set_simple (caps, "channels", G_TYPE_INT, max, NULL); + } else { + gst_caps_set_simple (caps, "channels", GST_TYPE_INT_RANGE, min, max, NULL); + } + + return caps; +} + +static GstRingBuffer * +gst_osx_audio_src_create_ringbuffer (GstBaseAudioSrc * src) +{ + GstOsxAudioSrc *osxsrc; + GstOsxRingBuffer *ringbuffer; + + osxsrc = GST_OSX_AUDIO_SRC (src); + + gst_osx_audio_src_select_device (osxsrc); + + GST_DEBUG ("Creating ringbuffer"); + ringbuffer = g_object_new (GST_TYPE_OSX_RING_BUFFER, NULL); + GST_DEBUG ("osx src 0x%p element 0x%p ioproc 0x%p", osxsrc, + GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsrc), + (void *) gst_osx_audio_src_io_proc); + + ringbuffer->element = GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsrc); + ringbuffer->is_src = TRUE; + ringbuffer->device_id = osxsrc->device_id; + + return GST_RING_BUFFER (ringbuffer); +} + +static OSStatus +gst_osx_audio_src_io_proc (GstOsxRingBuffer * buf, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * bufferList) +{ + OSStatus status; + guint8 *writeptr; + gint writeseg; + gint len; + gint remaining; + gint offset = 0; + + status = AudioUnitRender (buf->audiounit, ioActionFlags, inTimeStamp, + inBusNumber, inNumberFrames, buf->recBufferList); + + if (status) { + GST_WARNING_OBJECT (buf, "AudioUnitRender returned %d", (int) status); + return status; + } + + remaining = buf->recBufferList->mBuffers[0].mDataByteSize; + + while (remaining) { + if (!gst_ring_buffer_prepare_read (GST_RING_BUFFER (buf), + &writeseg, &writeptr, &len)) + return 0; + + len -= buf->segoffset; + + if (len > remaining) + len = remaining; + + memcpy (writeptr + buf->segoffset, + (char *) buf->recBufferList->mBuffers[0].mData + offset, len); + + buf->segoffset += len; + offset += len; + remaining -= len; + + if ((gint) buf->segoffset == GST_RING_BUFFER (buf)->spec.segsize) { + /* we wrote one segment */ + gst_ring_buffer_advance (GST_RING_BUFFER (buf), 1); + + buf->segoffset = 0; + } + } + return 0; +} + +static void +gst_osx_audio_src_osxelement_init (gpointer g_iface, gpointer iface_data) +{ + GstOsxAudioElementInterface *iface = (GstOsxAudioElementInterface *) g_iface; + + iface->io_proc = (AURenderCallback) gst_osx_audio_src_io_proc; +} + +static void +gst_osx_audio_src_select_device (GstOsxAudioSrc * osxsrc) +{ + OSStatus status; + UInt32 propertySize; + + if (osxsrc->device_id == kAudioDeviceUnknown) { + /* If no specific device has been selected by the user, then pick the + * default device */ + GST_DEBUG_OBJECT (osxsrc, "Selecting device for OSXAudioSrc"); + propertySize = sizeof (osxsrc->device_id); + status = AudioHardwareGetProperty (kAudioHardwarePropertyDefaultInputDevice, + &propertySize, &osxsrc->device_id); + + if (status) { + GST_WARNING_OBJECT (osxsrc, + "AudioHardwareGetProperty returned %d", (int) status); + } else { + GST_DEBUG_OBJECT (osxsrc, "AudioHardwareGetProperty returned 0"); + } + + if (osxsrc->device_id == kAudioDeviceUnknown) { + GST_WARNING_OBJECT (osxsrc, + "AudioHardwareGetProperty: device_id is kAudioDeviceUnknown"); + } + + GST_DEBUG_OBJECT (osxsrc, "AudioHardwareGetProperty: device_id is %lu", + (long) osxsrc->device_id); + } +} diff --git a/sys/osxaudio/gstosxaudiosrc.h b/sys/osxaudio/gstosxaudiosrc.h new file mode 100644 index 0000000..a812d9e --- /dev/null +++ b/sys/osxaudio/gstosxaudiosrc.h @@ -0,0 +1,82 @@ +/* + * GStreamer + * Copyright (C) 2005-2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * + * 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_OSXAUDIOSRC_H__ +#define __GST_OSXAUDIOSRC_H__ + +#include <gst/gst.h> +#include <gst/audio/gstbaseaudiosrc.h> +#include "gstosxringbuffer.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OSX_AUDIO_SRC \ + (gst_osx_audio_src_get_type()) +#define GST_OSX_AUDIO_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSX_AUDIO_SRC,GstOsxAudioSrc)) +#define GST_OSX_AUDIO_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_AUDIO_SRC,GstOsxAudioSrcClass)) + +typedef struct _GstOsxAudioSrc GstOsxAudioSrc; +typedef struct _GstOsxAudioSrcClass GstOsxAudioSrcClass; + +struct _GstOsxAudioSrc +{ + GstBaseAudioSrc src; + + AudioDeviceID device_id; + + /* actual number of channels reported by input device */ + int deviceChannels; +}; + +struct _GstOsxAudioSrcClass +{ + GstBaseAudioSrcClass parent_class; +}; + +GType gst_osx_audio_src_get_type (void); + +G_END_DECLS + +#endif /* __GST_OSXAUDIOSRC_H__ */ diff --git a/sys/osxaudio/gstosxringbuffer.c b/sys/osxaudio/gstosxringbuffer.c new file mode 100644 index 0000000..095efc1 --- /dev/null +++ b/sys/osxaudio/gstosxringbuffer.c @@ -0,0 +1,689 @@ +/* + * GStreamer + * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2008 Pioneers of the Inevitable <songbird@songbirdnest.com> + * + * 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. + */ + +#include <CoreAudio/CoreAudio.h> +#include <CoreServices/CoreServices.h> +#include <gst/gst.h> +#include <gst/audio/multichannel.h> +#include "gstosxringbuffer.h" +#include "gstosxaudiosink.h" +#include "gstosxaudiosrc.h" + +GST_DEBUG_CATEGORY_STATIC (osx_audio_debug); +#define GST_CAT_DEFAULT osx_audio_debug + +static void gst_osx_ring_buffer_dispose (GObject * object); +static void gst_osx_ring_buffer_finalize (GObject * object); +static gboolean gst_osx_ring_buffer_open_device (GstRingBuffer * buf); +static gboolean gst_osx_ring_buffer_close_device (GstRingBuffer * buf); + +static gboolean gst_osx_ring_buffer_acquire (GstRingBuffer * buf, + GstRingBufferSpec * spec); +static gboolean gst_osx_ring_buffer_release (GstRingBuffer * buf); + +static gboolean gst_osx_ring_buffer_start (GstRingBuffer * buf); +static gboolean gst_osx_ring_buffer_pause (GstRingBuffer * buf); +static gboolean gst_osx_ring_buffer_stop (GstRingBuffer * buf); +static guint gst_osx_ring_buffer_delay (GstRingBuffer * buf); +static GstRingBufferClass *ring_parent_class = NULL; + +static OSStatus gst_osx_ring_buffer_render_notify (GstOsxRingBuffer * osxbuf, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, unsigned int inBusNumber, + unsigned int inNumberFrames, AudioBufferList * ioData); + +static AudioBufferList *buffer_list_alloc (int channels, int size); +static void buffer_list_free (AudioBufferList * list); + +static void +gst_osx_ring_buffer_do_init (GType type) +{ + GST_DEBUG_CATEGORY_INIT (osx_audio_debug, "osxaudio", 0, + "OSX Audio Elements"); +} + +GST_BOILERPLATE_FULL (GstOsxRingBuffer, gst_osx_ring_buffer, GstRingBuffer, + GST_TYPE_RING_BUFFER, gst_osx_ring_buffer_do_init); + +static void +gst_osx_ring_buffer_base_init (gpointer g_class) +{ + /* Nothing to do right now */ +} + +static void +gst_osx_ring_buffer_class_init (GstOsxRingBufferClass * klass) +{ + GObjectClass *gobject_class; + GstObjectClass *gstobject_class; + GstRingBufferClass *gstringbuffer_class; + + gobject_class = (GObjectClass *) klass; + gstobject_class = (GstObjectClass *) klass; + gstringbuffer_class = (GstRingBufferClass *) klass; + + ring_parent_class = g_type_class_peek_parent (klass); + + gobject_class->dispose = gst_osx_ring_buffer_dispose; + gobject_class->finalize = gst_osx_ring_buffer_finalize; + + gstringbuffer_class->open_device = + GST_DEBUG_FUNCPTR (gst_osx_ring_buffer_open_device); + gstringbuffer_class->close_device = + GST_DEBUG_FUNCPTR (gst_osx_ring_buffer_close_device); + gstringbuffer_class->acquire = + GST_DEBUG_FUNCPTR (gst_osx_ring_buffer_acquire); + gstringbuffer_class->release = + GST_DEBUG_FUNCPTR (gst_osx_ring_buffer_release); + gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_osx_ring_buffer_start); + gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_osx_ring_buffer_pause); + gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_osx_ring_buffer_start); + gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_osx_ring_buffer_stop); + + gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_osx_ring_buffer_delay); + + GST_DEBUG ("osx ring buffer class init"); +} + +static void +gst_osx_ring_buffer_init (GstOsxRingBuffer * ringbuffer, + GstOsxRingBufferClass * g_class) +{ + /* Nothing to do right now */ +} + +static void +gst_osx_ring_buffer_dispose (GObject * object) +{ + G_OBJECT_CLASS (ring_parent_class)->dispose (object); +} + +static void +gst_osx_ring_buffer_finalize (GObject * object) +{ + G_OBJECT_CLASS (ring_parent_class)->finalize (object); +} + +static AudioUnit +gst_osx_ring_buffer_create_audio_unit (GstOsxRingBuffer * osxbuf, + gboolean input, AudioDeviceID device_id) +{ + ComponentDescription desc; + Component comp; + OSStatus status; + AudioUnit unit; + UInt32 enableIO; + + /* Create a HALOutput AudioUnit. + * This is the lowest-level output API that is actually sensibly usable + * (the lower level ones require that you do channel-remapping yourself, + * and the CoreAudio channel mapping is sufficiently complex that doing + * so would be very difficult) + * + * Note that for input we request an output unit even though we will do + * input with it: http://developer.apple.com/technotes/tn2002/tn2091.html + */ + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_HALOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + comp = FindNextComponent (NULL, &desc); + if (comp == NULL) { + GST_WARNING_OBJECT (osxbuf, "Couldn't find HALOutput component"); + return NULL; + } + + status = OpenAComponent (comp, &unit); + + if (status) { + GST_WARNING_OBJECT (osxbuf, "Couldn't open HALOutput component"); + return NULL; + } + + if (input) { + /* enable input */ + enableIO = 1; + status = AudioUnitSetProperty (unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, /* 1 = input element */ + &enableIO, sizeof (enableIO)); + + if (status) { + CloseComponent (unit); + GST_WARNING_OBJECT (osxbuf, "Failed to enable input: %lx", + (gulong) status); + return NULL; + } + + /* disable output */ + enableIO = 0; + status = AudioUnitSetProperty (unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, /* 0 = output element */ + &enableIO, sizeof (enableIO)); + + if (status) { + CloseComponent (unit); + GST_WARNING_OBJECT (osxbuf, "Failed to disable output: %lx", + (gulong) status); + return NULL; + } + } + + /* Specify which device we're using. */ + GST_DEBUG_OBJECT (osxbuf, "Setting device to %d", (int) device_id); + status = AudioUnitSetProperty (unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, /* N/A for global */ + &device_id, sizeof (AudioDeviceID)); + + if (status) { + CloseComponent (unit); + GST_WARNING_OBJECT (osxbuf, "Failed to set device: %lx", (gulong) status); + return NULL; + } + + GST_DEBUG_OBJECT (osxbuf, "Create HALOutput AudioUnit: %p", unit); + + return unit; +} + +static gboolean +gst_osx_ring_buffer_open_device (GstRingBuffer * buf) +{ + GstOsxRingBuffer *osxbuf; + GstOsxAudioSink *sink; + GstOsxAudioSrc *src; + AudioStreamBasicDescription asbd_in; + OSStatus status; + UInt32 propertySize; + + osxbuf = GST_OSX_RING_BUFFER (buf); + sink = NULL; + src = NULL; + + osxbuf->audiounit = gst_osx_ring_buffer_create_audio_unit (osxbuf, + osxbuf->is_src, osxbuf->device_id); + + if (osxbuf->is_src) { + src = GST_OSX_AUDIO_SRC (GST_OBJECT_PARENT (buf)); + + propertySize = sizeof (asbd_in); + status = AudioUnitGetProperty (osxbuf->audiounit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, 1, &asbd_in, &propertySize); + + if (status) { + CloseComponent (osxbuf->audiounit); + osxbuf->audiounit = NULL; + GST_WARNING_OBJECT (osxbuf, "Unable to obtain device properties: %lx", + (gulong) status); + return FALSE; + } + + src->deviceChannels = asbd_in.mChannelsPerFrame; + } else { + sink = GST_OSX_AUDIO_SINK (GST_OBJECT_PARENT (buf)); + + /* needed for the sink's volume control */ + sink->audiounit = osxbuf->audiounit; + } + + return TRUE; +} + +static gboolean +gst_osx_ring_buffer_close_device (GstRingBuffer * buf) +{ + GstOsxRingBuffer *osxbuf; + osxbuf = GST_OSX_RING_BUFFER (buf); + + CloseComponent (osxbuf->audiounit); + osxbuf->audiounit = NULL; + + return TRUE; +} + +static AudioChannelLabel +gst_audio_channel_position_to_coreaudio_channel_label (GstAudioChannelPosition + position, int channel) +{ + switch (position) { + case GST_AUDIO_CHANNEL_POSITION_NONE: + return kAudioChannelLabel_Discrete_0 | channel; + case GST_AUDIO_CHANNEL_POSITION_FRONT_MONO: + return kAudioChannelLabel_Mono; + case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT: + return kAudioChannelLabel_Left; + case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT: + return kAudioChannelLabel_Right; + case GST_AUDIO_CHANNEL_POSITION_REAR_CENTER: + return kAudioChannelLabel_CenterSurround; + case GST_AUDIO_CHANNEL_POSITION_REAR_LEFT: + return kAudioChannelLabel_LeftSurround; + case GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT: + return kAudioChannelLabel_RightSurround; + case GST_AUDIO_CHANNEL_POSITION_LFE: + return kAudioChannelLabel_LFEScreen; + case GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER: + return kAudioChannelLabel_Center; + case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: + return kAudioChannelLabel_Center; // ??? + case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: + return kAudioChannelLabel_Center; // ??? + case GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT: + return kAudioChannelLabel_LeftSurroundDirect; + case GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT: + return kAudioChannelLabel_RightSurroundDirect; + default: + return kAudioChannelLabel_Unknown; + } +} + +static gboolean +gst_osx_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) +{ + /* Configure the output stream and allocate ringbuffer memory */ + GstOsxRingBuffer *osxbuf; + AudioStreamBasicDescription format; + AudioChannelLayout *layout = NULL; + OSStatus status; + UInt32 propertySize; + int layoutSize; + int element; + int i; + AudioUnitScope scope; + gboolean ret = FALSE; + GstStructure *structure; + GstAudioChannelPosition *positions; + UInt32 frameSize; + + osxbuf = GST_OSX_RING_BUFFER (buf); + + /* Fill out the audio description we're going to be using */ + format.mFormatID = kAudioFormatLinearPCM; + format.mSampleRate = (double) spec->rate; + format.mChannelsPerFrame = spec->channels; + format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; + format.mBytesPerFrame = spec->channels * sizeof (float); + format.mBitsPerChannel = sizeof (float) * 8; + format.mBytesPerPacket = spec->channels * sizeof (float); + format.mFramesPerPacket = 1; + format.mReserved = 0; + + /* Describe channels */ + layoutSize = sizeof (AudioChannelLayout) + + spec->channels * sizeof (AudioChannelDescription); + layout = g_malloc (layoutSize); + + structure = gst_caps_get_structure (spec->caps, 0); + positions = gst_audio_get_channel_positions (structure); + + layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions; + layout->mChannelBitmap = 0; /* Not used */ + layout->mNumberChannelDescriptions = spec->channels; + for (i = 0; i < spec->channels; i++) { + if (positions) { + layout->mChannelDescriptions[i].mChannelLabel = + gst_audio_channel_position_to_coreaudio_channel_label (positions[i], + i); + } else { + /* Discrete channel numbers are ORed into this */ + layout->mChannelDescriptions[i].mChannelLabel = + kAudioChannelLabel_Discrete_0 | i; + } + + /* Others unused */ + layout->mChannelDescriptions[i].mChannelFlags = 0; + layout->mChannelDescriptions[i].mCoordinates[0] = 0.f; + layout->mChannelDescriptions[i].mCoordinates[1] = 0.f; + layout->mChannelDescriptions[i].mCoordinates[2] = 0.f; + } + + if (positions) { + g_free (positions); + positions = NULL; + } + + GST_LOG_OBJECT (osxbuf, "Format: %x, %f, %u, %x, %d, %d, %d, %d, %d", + (unsigned int) format.mFormatID, + format.mSampleRate, + (unsigned int) format.mChannelsPerFrame, + (unsigned int) format.mFormatFlags, + (unsigned int) format.mBytesPerFrame, + (unsigned int) format.mBitsPerChannel, + (unsigned int) format.mBytesPerPacket, + (unsigned int) format.mFramesPerPacket, (unsigned int) format.mReserved); + + GST_DEBUG_OBJECT (osxbuf, "Setting format for AudioUnit"); + + scope = osxbuf->is_src ? kAudioUnitScope_Output : kAudioUnitScope_Input; + element = osxbuf->is_src ? 1 : 0; + + propertySize = sizeof (format); + status = AudioUnitSetProperty (osxbuf->audiounit, + kAudioUnitProperty_StreamFormat, scope, element, &format, propertySize); + + if (status) { + GST_WARNING_OBJECT (osxbuf, "Failed to set audio description: %lx", + (gulong) status); + goto done; + } + + status = AudioUnitSetProperty (osxbuf->audiounit, + kAudioUnitProperty_AudioChannelLayout, + scope, element, layout, layoutSize); + if (status) { + GST_WARNING_OBJECT (osxbuf, "Failed to set output channel layout: %lx", + (gulong) status); + goto done; + } + + spec->segsize = + (spec->latency_time * spec->rate / G_USEC_PER_SEC) * + spec->bytes_per_sample; + spec->segtotal = spec->buffer_time / spec->latency_time; + + /* create AudioBufferList needed for recording */ + if (osxbuf->is_src) { + propertySize = sizeof (frameSize); + status = AudioUnitGetProperty (osxbuf->audiounit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, /* N/A for global */ + &frameSize, &propertySize); + + if (status) { + GST_WARNING_OBJECT (osxbuf, "Failed to get frame size: %lx", + (gulong) status); + goto done; + } + + osxbuf->recBufferList = buffer_list_alloc (format.mChannelsPerFrame, + frameSize * format.mBytesPerFrame); + } + + buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize); + memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data)); + + osxbuf->segoffset = 0; + + status = AudioUnitInitialize (osxbuf->audiounit); + if (status) { + gst_buffer_unref (buf->data); + buf->data = NULL; + + if (osxbuf->recBufferList) { + buffer_list_free (osxbuf->recBufferList); + osxbuf->recBufferList = NULL; + } + + GST_WARNING_OBJECT (osxbuf, + "Failed to initialise AudioUnit: %d", (int) status); + goto done; + } + + GST_DEBUG_OBJECT (osxbuf, "osx ring buffer acquired"); + + ret = TRUE; + +done: + g_free (layout); + return ret; +} + +static gboolean +gst_osx_ring_buffer_release (GstRingBuffer * buf) +{ + GstOsxRingBuffer *osxbuf; + + osxbuf = GST_OSX_RING_BUFFER (buf); + + AudioUnitUninitialize (osxbuf->audiounit); + + gst_buffer_unref (buf->data); + buf->data = NULL; + + if (osxbuf->recBufferList) { + buffer_list_free (osxbuf->recBufferList); + osxbuf->recBufferList = NULL; + } + + return TRUE; +} + +static void +gst_osx_ring_buffer_remove_render_callback (GstOsxRingBuffer * osxbuf) +{ + AURenderCallbackStruct input; + OSStatus status; + + /* Deactivate the render callback by calling SetRenderCallback with a NULL + * inputProc. + */ + input.inputProc = NULL; + input.inputProcRefCon = NULL; + + status = AudioUnitSetProperty (osxbuf->audiounit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, /* N/A for global */ + &input, sizeof (input)); + + if (status) { + GST_WARNING_OBJECT (osxbuf, "Failed to remove render callback"); + } + + /* Remove the RenderNotify too */ + status = AudioUnitRemoveRenderNotify (osxbuf->audiounit, + (AURenderCallback) gst_osx_ring_buffer_render_notify, osxbuf); + + if (status) { + GST_WARNING_OBJECT (osxbuf, "Failed to remove render notify callback"); + } + + /* We're deactivated.. */ + osxbuf->io_proc_needs_deactivation = FALSE; + osxbuf->io_proc_active = FALSE; +} + +static OSStatus +gst_osx_ring_buffer_render_notify (GstOsxRingBuffer * osxbuf, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + unsigned int inBusNumber, + unsigned int inNumberFrames, AudioBufferList * ioData) +{ + /* Before rendering a frame, we get the PreRender notification. + * Here, we detach the RenderCallback if we've been paused. + * + * This is necessary (rather than just directly detaching it) to work + * around some thread-safety issues in CoreAudio + */ + if ((*ioActionFlags) & kAudioUnitRenderAction_PreRender) { + if (osxbuf->io_proc_needs_deactivation) { + gst_osx_ring_buffer_remove_render_callback (osxbuf); + } + } + + return noErr; +} + +static gboolean +gst_osx_ring_buffer_start (GstRingBuffer * buf) +{ + OSStatus status; + GstOsxRingBuffer *osxbuf; + AURenderCallbackStruct input; + AudioUnitPropertyID callback_type; + + osxbuf = GST_OSX_RING_BUFFER (buf); + + GST_DEBUG ("osx ring buffer start ioproc: 0x%p device_id %lu", + osxbuf->element->io_proc, (gulong) osxbuf->device_id); + if (!osxbuf->io_proc_active) { + callback_type = osxbuf->is_src ? + kAudioOutputUnitProperty_SetInputCallback : + kAudioUnitProperty_SetRenderCallback; + + input.inputProc = (AURenderCallback) osxbuf->element->io_proc; + input.inputProcRefCon = osxbuf; + + status = AudioUnitSetProperty (osxbuf->audiounit, callback_type, kAudioUnitScope_Global, 0, /* N/A for global */ + &input, sizeof (input)); + + if (status) { + GST_WARNING ("AudioUnitSetProperty returned %d", (int) status); + return FALSE; + } + // ### does it make sense to do this notify stuff for input mode? + status = AudioUnitAddRenderNotify (osxbuf->audiounit, + (AURenderCallback) gst_osx_ring_buffer_render_notify, osxbuf); + + if (status) { + GST_WARNING ("AudioUnitAddRenderNotify returned %d", (int) status); + return FALSE; + } + + osxbuf->io_proc_active = TRUE; + } + + osxbuf->io_proc_needs_deactivation = FALSE; + + status = AudioOutputUnitStart (osxbuf->audiounit); + if (status) { + GST_WARNING ("AudioOutputUnitStart returned %d", (int) status); + return FALSE; + } + return TRUE; +} + +// ### +static gboolean +gst_osx_ring_buffer_pause (GstRingBuffer * buf) +{ + GstOsxRingBuffer *osxbuf = GST_OSX_RING_BUFFER (buf); + + GST_DEBUG ("osx ring buffer pause ioproc: 0x%p device_id %lu", + osxbuf->element->io_proc, (gulong) osxbuf->device_id); + if (osxbuf->io_proc_active) { + /* CoreAudio isn't threadsafe enough to do this here; we must deactivate + * the render callback elsewhere. See: + * http://lists.apple.com/archives/Coreaudio-api/2006/Mar/msg00010.html + */ + osxbuf->io_proc_needs_deactivation = TRUE; + } + return TRUE; +} + +// ### +static gboolean +gst_osx_ring_buffer_stop (GstRingBuffer * buf) +{ + OSErr status; + GstOsxRingBuffer *osxbuf; + + osxbuf = GST_OSX_RING_BUFFER (buf); + + GST_DEBUG ("osx ring buffer stop ioproc: 0x%p device_id %lu", + osxbuf->element->io_proc, (gulong) osxbuf->device_id); + + status = AudioOutputUnitStop (osxbuf->audiounit); + if (status) + GST_WARNING ("AudioOutputUnitStop returned %d", (int) status); + + // ###: why is it okay to directly remove from here but not from pause() ? + if (osxbuf->io_proc_active) { + gst_osx_ring_buffer_remove_render_callback (osxbuf); + } + return TRUE; +} + +static guint +gst_osx_ring_buffer_delay (GstRingBuffer * buf) +{ + double latency; + UInt32 size = sizeof (double); + GstOsxRingBuffer *osxbuf; + OSStatus status; + guint samples; + + osxbuf = GST_OSX_RING_BUFFER (buf); + + status = AudioUnitGetProperty (osxbuf->audiounit, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, /* N/A for global */ + &latency, &size); + + if (status) { + GST_WARNING_OBJECT (buf, "Failed to get latency: %d", (int) status); + return 0; + } + + samples = latency * GST_RING_BUFFER (buf)->spec.rate; + GST_DEBUG_OBJECT (buf, "Got latency: %f seconds -> %d samples", latency, + samples); + return samples; +} + +static AudioBufferList * +buffer_list_alloc (int channels, int size) +{ + AudioBufferList *list; + int total_size; + int n; + + total_size = sizeof (AudioBufferList) + 1 * sizeof (AudioBuffer); + list = (AudioBufferList *) g_malloc (total_size); + + list->mNumberBuffers = 1; + for (n = 0; n < (int) list->mNumberBuffers; ++n) { + list->mBuffers[n].mNumberChannels = channels; + list->mBuffers[n].mDataByteSize = size; + list->mBuffers[n].mData = g_malloc (size); + } + + return list; +} + +static void +buffer_list_free (AudioBufferList * list) +{ + int n; + + for (n = 0; n < (int) list->mNumberBuffers; ++n) { + if (list->mBuffers[n].mData) + g_free (list->mBuffers[n].mData); + } + + g_free (list); +} diff --git a/sys/osxaudio/gstosxringbuffer.h b/sys/osxaudio/gstosxringbuffer.h new file mode 100644 index 0000000..5e6dbe4 --- /dev/null +++ b/sys/osxaudio/gstosxringbuffer.h @@ -0,0 +1,94 @@ +/* + * GStreamer + * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * + * 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_OSX_RING_BUFFER_H__ +#define __GST_OSX_RING_BUFFER_H__ + +#include <gst/gst.h> +#include <gst/audio/gstringbuffer.h> +#include <CoreAudio/CoreAudio.h> +#include "gstosxaudioelement.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OSX_RING_BUFFER \ + (gst_osx_ring_buffer_get_type()) +#define GST_OSX_RING_BUFFER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSX_RING_BUFFER,GstOsxRingBuffer)) +#define GST_OSX_RING_BUFFER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_RING_BUFFER,GstOsxRingBufferClass)) +#define GST_OSX_RING_BUFFER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_OSX_RING_BUFFER,GstOsxRingBufferClass)) +#define GST_IS_OSX_RING_BUFFER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSX_RING_BUFFER)) +#define GST_IS_OSX_RING_BUFFER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSX_RING_BUFFER)) + +typedef struct _GstOsxRingBuffer GstOsxRingBuffer; +typedef struct _GstOsxRingBufferClass GstOsxRingBufferClass; + +struct _GstOsxRingBuffer +{ + GstRingBuffer object; + + gboolean is_src; + AudioUnit audiounit; + AudioDeviceID device_id; + gboolean io_proc_active; + gboolean io_proc_needs_deactivation; + guint buffer_len; + guint segoffset; + AudioBufferList * recBufferList; + GstOsxAudioElementInterface * element; +}; + +struct _GstOsxRingBufferClass +{ + GstRingBufferClass parent_class; +}; + +GType gst_osx_ring_buffer_get_type (void); + +G_END_DECLS + +#endif /* __GST_OSX_RING_BUFFER_H__ */ diff --git a/sys/osxvideo/Makefile.am b/sys/osxvideo/Makefile.am new file mode 100644 index 0000000..8893c2e --- /dev/null +++ b/sys/osxvideo/Makefile.am @@ -0,0 +1,19 @@ + +plugin_LTLIBRARIES = libgstosxvideosink.la + +libgstosxvideosink_la_SOURCES = osxvideosink.m cocoawindow.m +libgstosxvideosink_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) +libgstosxvideosink_la_LIBADD = \ + $(GST_LIBS) \ + $(GST_BASE_LIBS) \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstvideo-$(GST_MAJORMINOR) \ + -lgstinterfaces-$(GST_MAJORMINOR) + +libgstosxvideosink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -Wl,-framework -Wl,Cocoa -Wl,-framework -Wl,QuickTime -Wl,-framework -Wl,OpenGL +libgstosxvideosink_la_LIBTOOLFLAGS = --tag=disable-static + +AM_OBJCFLAGS=$(CFLAGS) $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) -Wno-aggregate-return + +noinst_HEADERS = osxvideosink.h cocoawindow.h diff --git a/sys/osxvideo/Makefile.in b/sys/osxvideo/Makefile.in new file mode 100644 index 0000000..fe62cb4 --- /dev/null +++ b/sys/osxvideo/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 = sys/osxvideo +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 = +libgstosxvideosink_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgstosxvideosink_la_OBJECTS = \ + libgstosxvideosink_la-osxvideosink.lo \ + libgstosxvideosink_la-cocoawindow.lo +libgstosxvideosink_la_OBJECTS = $(am_libgstosxvideosink_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +libgstosxvideosink_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + $(libgstosxvideosink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(OBJCLD) $(AM_OBJCFLAGS) $(OBJCFLAGS) \ + $(libgstosxvideosink_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 +OBJCCOMPILE = $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_OBJCFLAGS) $(OBJCFLAGS) +LTOBJCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_OBJCFLAGS) $(OBJCFLAGS) +AM_V_OBJC = $(am__v_OBJC_@AM_V@) +am__v_OBJC_ = $(am__v_OBJC_@AM_DEFAULT_V@) +am__v_OBJC_0 = @echo " OBJC " $@; +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +OBJCLD = $(OBJC) +OBJCLINK = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(OBJCLD) $(AM_OBJCFLAGS) $(OBJCFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_OBJCLD = $(am__v_OBJCLD_@AM_V@) +am__v_OBJCLD_ = $(am__v_OBJCLD_@AM_DEFAULT_V@) +am__v_OBJCLD_0 = @echo " OBJCLD" $@; +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libgstosxvideosink_la_SOURCES) +DIST_SOURCES = $(libgstosxvideosink_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 = libgstosxvideosink.la +libgstosxvideosink_la_SOURCES = osxvideosink.m cocoawindow.m +libgstosxvideosink_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) + +libgstosxvideosink_la_LIBADD = \ + $(GST_LIBS) \ + $(GST_BASE_LIBS) \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstvideo-$(GST_MAJORMINOR) \ + -lgstinterfaces-$(GST_MAJORMINOR) + +libgstosxvideosink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -Wl,-framework -Wl,Cocoa -Wl,-framework -Wl,QuickTime -Wl,-framework -Wl,OpenGL +libgstosxvideosink_la_LIBTOOLFLAGS = --tag=disable-static +AM_OBJCFLAGS = $(CFLAGS) $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) -Wno-aggregate-return +noinst_HEADERS = osxvideosink.h cocoawindow.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .lo .m .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 sys/osxvideo/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu sys/osxvideo/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 +libgstosxvideosink.la: $(libgstosxvideosink_la_OBJECTS) $(libgstosxvideosink_la_DEPENDENCIES) $(EXTRA_libgstosxvideosink_la_DEPENDENCIES) + $(AM_V_OBJCLD)$(libgstosxvideosink_la_LINK) -rpath $(plugindir) $(libgstosxvideosink_la_OBJECTS) $(libgstosxvideosink_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxvideosink_la-cocoawindow.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxvideosink_la-osxvideosink.Plo@am__quote@ + +.m.o: +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(OBJCCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(OBJCCOMPILE) -c -o $@ $< + +.m.obj: +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(OBJCCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(OBJCCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.m.lo: +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LTOBJCCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LTOBJCCOMPILE) -c -o $@ $< + +libgstosxvideosink_la-osxvideosink.lo: osxvideosink.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(libgstosxvideosink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_OBJCFLAGS) $(OBJCFLAGS) -MT libgstosxvideosink_la-osxvideosink.lo -MD -MP -MF $(DEPDIR)/libgstosxvideosink_la-osxvideosink.Tpo -c -o libgstosxvideosink_la-osxvideosink.lo `test -f 'osxvideosink.m' || echo '$(srcdir)/'`osxvideosink.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxvideosink_la-osxvideosink.Tpo $(DEPDIR)/libgstosxvideosink_la-osxvideosink.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='osxvideosink.m' object='libgstosxvideosink_la-osxvideosink.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(libgstosxvideosink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_OBJCFLAGS) $(OBJCFLAGS) -c -o libgstosxvideosink_la-osxvideosink.lo `test -f 'osxvideosink.m' || echo '$(srcdir)/'`osxvideosink.m + +libgstosxvideosink_la-cocoawindow.lo: cocoawindow.m +@am__fastdepOBJC_TRUE@ $(AM_V_OBJC)$(LIBTOOL) $(AM_V_lt) $(libgstosxvideosink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_OBJCFLAGS) $(OBJCFLAGS) -MT libgstosxvideosink_la-cocoawindow.lo -MD -MP -MF $(DEPDIR)/libgstosxvideosink_la-cocoawindow.Tpo -c -o libgstosxvideosink_la-cocoawindow.lo `test -f 'cocoawindow.m' || echo '$(srcdir)/'`cocoawindow.m +@am__fastdepOBJC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxvideosink_la-cocoawindow.Tpo $(DEPDIR)/libgstosxvideosink_la-cocoawindow.Plo +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ $(AM_V_OBJC)source='cocoawindow.m' object='libgstosxvideosink_la-cocoawindow.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepOBJC_FALSE@ DEPDIR=$(DEPDIR) $(OBJCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepOBJC_FALSE@ $(AM_V_OBJC@am__nodep@)$(LIBTOOL) $(AM_V_lt) $(libgstosxvideosink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(OBJC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_OBJCFLAGS) $(OBJCFLAGS) -c -o libgstosxvideosink_la-cocoawindow.lo `test -f 'cocoawindow.m' || echo '$(srcdir)/'`cocoawindow.m + +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/sys/osxvideo/cocoawindow.h b/sys/osxvideo/cocoawindow.h new file mode 100644 index 0000000..7324cc7 --- /dev/null +++ b/sys/osxvideo/cocoawindow.h @@ -0,0 +1,74 @@ +/* GStreamer + * Copyright (C) 2004 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.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. + * + * The development of this code was made possible due to the involvement of Pioneers + * of the Inevitable, the creators of the Songbird Music player + * + */ + +/* inspiration gained from looking at source of osx video out of xine and vlc + * and is reflected in the code + */ + +#import <Cocoa/Cocoa.h> +#import <QuickTime/QuickTime.h> +#import <glib.h> + +struct _GstOSXImage; + +@interface GstGLView : NSOpenGLView +{ + int i_effect; + unsigned int pi_texture; + float f_x; + float f_y; + int initDone; + char* data; + int width, height; + BOOL fullscreen; + NSOpenGLContext* fullScreenContext; + NSOpenGLContext* actualContext; +} +- (void) drawQuad; +- (void) drawRect: (NSRect) rect; +- (id) initWithFrame: (NSRect) frame; +- (void) initTextures; +- (void) reloadTexture; +- (void) cleanUp; +- (void) displayTexture; +- (char*) getTextureBuffer; +- (void) setFullScreen: (BOOL) flag; +- (void) reshape; +- (void) setVideoSize: (int) w: (int) h; +- (BOOL) haveSuperview; +- (void) haveSuperviewReal: (NSMutableArray *)closure; +- (void) addToSuperview: (NSView *)superview; +- (void) removeFromSuperview: (id)unused; + +@end + +@interface GstOSXVideoSinkWindow: NSWindow { + int width, height; + GstGLView *gstview; +} + +- (void) setContentSize: (NSSize) size; +- (GstGLView *) gstView; +- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag screen:(NSScreen *)aScreen; +@end diff --git a/sys/osxvideo/cocoawindow.m b/sys/osxvideo/cocoawindow.m new file mode 100644 index 0000000..ed24fad --- /dev/null +++ b/sys/osxvideo/cocoawindow.m @@ -0,0 +1,432 @@ +/* GStreamer + * Copyright (C) 2004 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.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. + * + * The development of this code was made possible due to the involvement of Pioneers + * of the Inevitable, the creators of the Songbird Music player + * + */ + +/* inspiration gained from looking at source of osx video out of xine and vlc + * and is reflected in the code + */ + + +#include <Cocoa/Cocoa.h> +#include <gst/gst.h> +#import "cocoawindow.h" +#import "osxvideosink.h" + +#include <OpenGL/OpenGL.h> +#include <OpenGL/gl.h> +#include <OpenGL/glext.h> + +/* Debugging category */ +#include <gst/gstinfo.h> + +@ implementation GstOSXVideoSinkWindow + +/* The object has to be released */ +- (id) initWithContentRect: (NSRect) rect + styleMask: (unsigned int) styleMask + backing: (NSBackingStoreType) bufferingType + defer: (BOOL) flag + screen:(NSScreen *) aScreen +{ + self = [super initWithContentRect: rect + styleMask: styleMask + backing: bufferingType + defer: flag + screen:aScreen]; + + GST_DEBUG ("Initializing GstOSXvideoSinkWindow"); + + gstview = [[GstGLView alloc] initWithFrame:rect]; + + if (gstview) + [self setContentView:gstview]; + [self setTitle:@"GStreamer Video Output"]; + + return self; +} + +- (void) setContentSize:(NSSize) size { + width = size.width; + height = size.height; + + [gstview setVideoSize: (int) width:(int) height]; + + [super setContentSize:size]; +} + +- (GstGLView *) gstView { + return gstview; +} + +- (void) awakeFromNib { + [self setAcceptsMouseMovedEvents:YES]; +} + +- (void) sendEvent:(NSEvent *) event { + BOOL taken = NO; + + GST_DEBUG ("event %p type:%d", event,(gint)[event type]); + + if ([event type] == NSKeyDown) { + } + /*taken = [gstview keyDown:event]; */ + + if (!taken) { + [super sendEvent:event]; + } +} + + +@end + + +// +// OpenGL implementation +// + +@ implementation GstGLView + +- (id) initWithFrame:(NSRect) frame { + NSOpenGLPixelFormat *fmt; + NSOpenGLPixelFormatAttribute attribs[] = { + NSOpenGLPFAAccelerated, + NSOpenGLPFANoRecovery, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAColorSize, 24, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFADepthSize, 24, + NSOpenGLPFAWindow, + 0 + }; + + fmt = [[NSOpenGLPixelFormat alloc] + initWithAttributes:attribs]; + + if (!fmt) { + GST_WARNING ("Cannot create NSOpenGLPixelFormat"); + return nil; + } + + self = [super initWithFrame: frame pixelFormat:fmt]; + [fmt release]; + + actualContext = [self openGLContext]; + [actualContext makeCurrentContext]; + [actualContext update]; + + /* Black background */ + glClearColor (0.0, 0.0, 0.0, 0.0); + + pi_texture = 0; + data = nil; + width = frame.size.width; + height = frame.size.height; + + GST_LOG ("Width: %d Height: %d", width, height); + + [self initTextures]; + return self; +} + +- (void) reshape { + NSRect bounds; + + GST_LOG ("reshaping"); + + if (!initDone) { + return; + } + + [actualContext makeCurrentContext]; + + bounds = [self bounds]; + + glViewport (0, 0, (GLint) bounds.size.width, (GLint) bounds.size.height); + +} + +- (void) initTextures { + + [actualContext makeCurrentContext]; + + /* Free previous texture if any */ + if (pi_texture) { + glDeleteTextures (1, (GLuint *)&pi_texture); + } + + if (data) { + data = g_realloc (data, width * height * sizeof(short)); // short or 3byte? + } else { + data = g_malloc0(width * height * sizeof(short)); + } + /* Create textures */ + glGenTextures (1, (GLuint *)&pi_texture); + + glEnable (GL_TEXTURE_RECTANGLE_EXT); + glEnable (GL_UNPACK_CLIENT_STORAGE_APPLE); + + glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + glPixelStorei (GL_UNPACK_ROW_LENGTH, width); + + glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture); + + /* Use VRAM texturing */ + glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, + GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE); + + /* Tell the driver not to make a copy of the texture but to use + our buffer */ + glPixelStorei (GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + + /* Linear interpolation */ + glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + /* I have no idea what this exactly does, but it seems to be + necessary for scaling */ + glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, + GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_EXT, + GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); WHY ?? + + glTexImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, + width, height, 0, + GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, data); + + + initDone = 1; +} + +- (void) reloadTexture { + if (!initDone) { + return; + } + + GST_LOG ("Reloading Texture"); + + [actualContext makeCurrentContext]; + + glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture); + glPixelStorei (GL_UNPACK_ROW_LENGTH, width); + + /* glTexSubImage2D is faster than glTexImage2D + http://developer.apple.com/samplecode/Sample_Code/Graphics_3D/ + TextureRange/MainOpenGLView.m.htm */ + glTexSubImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, + width, height, + GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, data); //FIXME +} + +- (void) cleanUp { + initDone = 0; +} + +- (void) drawQuad { + f_x = 1.0; + f_y = 1.0; + + glBegin (GL_QUADS); + /* Top left */ + glTexCoord2f (0.0, 0.0); + glVertex2f (-f_x, f_y); + /* Bottom left */ + glTexCoord2f (0.0, (float) height); + glVertex2f (-f_x, -f_y); + /* Bottom right */ + glTexCoord2f ((float) width, (float) height); + glVertex2f (f_x, -f_y); + /* Top right */ + glTexCoord2f ((float) width, 0.0); + glVertex2f (f_x, f_y); + glEnd (); +} + +- (void) drawRect:(NSRect) rect { + GLint params[] = { 1 }; + + [actualContext makeCurrentContext]; + + CGLSetParameter (CGLGetCurrentContext (), kCGLCPSwapInterval, params); + + /* Black background */ + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (!initDone) { + [actualContext flushBuffer]; + return; + } + + /* Draw */ + glBindTexture (GL_TEXTURE_RECTANGLE_EXT, pi_texture); // FIXME + [self drawQuad]; + /* Draw */ + [actualContext flushBuffer]; +} + +- (void) displayTexture { + if ([self lockFocusIfCanDraw]) { + + [self drawRect:[self bounds]]; + [self reloadTexture]; + + [self unlockFocus]; + + } + +} + +- (char *) getTextureBuffer { + return data; +} + +- (void) setFullScreen:(BOOL) flag { + if (!fullscreen && flag) { + // go to full screen + /* Create the new pixel format */ + NSOpenGLPixelFormat *fmt; + NSOpenGLPixelFormatAttribute attribs[] = { + NSOpenGLPFAAccelerated, + NSOpenGLPFANoRecovery, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAColorSize, 24, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFADepthSize, 24, + NSOpenGLPFAFullScreen, + NSOpenGLPFAScreenMask, + CGDisplayIDToOpenGLDisplayMask (kCGDirectMainDisplay), + 0 + }; + + fmt = [[NSOpenGLPixelFormat alloc] + initWithAttributes:attribs]; + + if (!fmt) { + GST_WARNING ("Cannot create NSOpenGLPixelFormat"); + return; + } + + /* Create the new OpenGL context */ + fullScreenContext = [[NSOpenGLContext alloc] + initWithFormat: fmt shareContext:nil]; + if (!fullScreenContext) { + GST_WARNING ("Failed to create new NSOpenGLContext"); + return; + } + + actualContext = fullScreenContext; + + /* Capture display, switch to fullscreen */ + if (CGCaptureAllDisplays () != CGDisplayNoErr) { + GST_WARNING ("CGCaptureAllDisplays() failed"); + return; + } + [fullScreenContext setFullScreen]; + [fullScreenContext makeCurrentContext]; + + fullscreen = YES; + + [self initTextures]; + [self setNeedsDisplay:YES]; + + } else if (fullscreen && !flag) { + // fullscreen now and needs to go back to normal + initDone = NO; + + actualContext = [self openGLContext]; + + [NSOpenGLContext clearCurrentContext]; + [fullScreenContext clearDrawable]; + [fullScreenContext release]; + fullScreenContext = nil; + + CGReleaseAllDisplays (); + + [self reshape]; + [self initTextures]; + + [self setNeedsDisplay:YES]; + + fullscreen = NO; + initDone = YES; + } +} + +- (void) setVideoSize: (int) w:(int) h { + GST_LOG ("width:%d, height:%d", w, h); + + width = w; + height = h; + +// if (data) g_free(data); + +// data = g_malloc0 (2 * w * h); + [self initTextures]; +} + +- (void) haveSuperviewReal:(NSMutableArray *)closure { + BOOL haveSuperview = [self superview] != nil; + [closure addObject:[NSNumber numberWithBool:haveSuperview]]; +} + +- (BOOL) haveSuperview { + NSMutableArray *closure = [NSMutableArray arrayWithCapacity:1]; + [self performSelectorOnMainThread:@selector(haveSuperviewReal:) + withObject:(id)closure waitUntilDone:YES]; + + return [[closure objectAtIndex:0] boolValue]; +} + +- (void) addToSuperviewReal:(NSView *)superview { + NSRect bounds; + [superview addSubview:self]; + bounds = [superview bounds]; + [self setFrame:bounds]; + [self setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; +} + +- (void) addToSuperview: (NSView *)superview { + [self performSelectorOnMainThread:@selector(addToSuperviewReal:) + withObject:superview waitUntilDone:YES]; +} + +- (void) removeFromSuperview: (id)unused +{ + [self removeFromSuperview]; +} + +- (void) dealloc { + GST_LOG ("dealloc called"); + if (data) g_free(data); + + if (fullScreenContext) { + [NSOpenGLContext clearCurrentContext]; + [fullScreenContext clearDrawable]; + [fullScreenContext release]; + if (actualContext == fullScreenContext) actualContext = nil; + fullScreenContext = nil; + } + + [super dealloc]; +} +@end diff --git a/sys/osxvideo/osxvideosink.h b/sys/osxvideo/osxvideosink.h new file mode 100644 index 0000000..2a228d0 --- /dev/null +++ b/sys/osxvideo/osxvideosink.h @@ -0,0 +1,85 @@ +/* GStreamer + * Copyright (C) 2004-6 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.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. + * + * + * The development of this code was made possible due to the involvement of Pioneers + * of the Inevitable, the creators of the Songbird Music player + * + */ + +#ifndef __GST_OSX_VIDEO_SINK_H__ +#define __GST_OSX_VIDEO_SINK_H__ + +#include <gst/video/gstvideosink.h> + +#include <string.h> +#include <math.h> +#include <Cocoa/Cocoa.h> + +#include <QuickTime/QuickTime.h> +#import "cocoawindow.h" + +GST_DEBUG_CATEGORY_EXTERN (gst_debug_osx_video_sink); +#define GST_CAT_DEFAULT gst_debug_osx_video_sink + +G_BEGIN_DECLS + +#define GST_TYPE_OSX_VIDEO_SINK \ + (gst_osx_video_sink_get_type()) +#define GST_OSX_VIDEO_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_OSX_VIDEO_SINK, GstOSXVideoSink)) +#define GST_OSX_VIDEO_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_OSX_VIDEO_SINK, GstOSXVideoSinkClass)) +#define GST_IS_OSX_VIDEO_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OSX_VIDEO_SINK)) +#define GST_IS_OSX_VIDEO_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_OSX_VIDEO_SINK)) + +typedef struct _GstOSXWindow GstOSXWindow; + +typedef struct _GstOSXVideoSink GstOSXVideoSink; +typedef struct _GstOSXVideoSinkClass GstOSXVideoSinkClass; + +#define GST_TYPE_OSXVIDEOBUFFER (gst_osxvideobuffer_get_type()) + +/* OSXWindow stuff */ +struct _GstOSXWindow { + gint width, height; + gboolean internal; + GstGLView* gstview; +}; + +struct _GstOSXVideoSink { + /* Our element stuff */ + GstVideoSink videosink; + GstOSXWindow *osxwindow; + NSView *superview; +}; + +struct _GstOSXVideoSinkClass { + GstVideoSinkClass parent_class; +}; + +GType gst_osx_video_sink_get_type(void); + +G_END_DECLS + +#endif /* __GST_OSX_VIDEO_SINK_H__ */ + diff --git a/sys/osxvideo/osxvideosink.m b/sys/osxvideo/osxvideosink.m new file mode 100644 index 0000000..5914550 --- /dev/null +++ b/sys/osxvideo/osxvideosink.m @@ -0,0 +1,524 @@ +/* GStreamer + * OSX video sink + * Copyright (C) 2004-6 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2007,2008,2009 Pioneers of the Inevitable <songbird@songbirdnest.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. + * + * The development of this code was made possible due to the involvement of + * Pioneers of the Inevitable, the creators of the Songbird Music player. + * + */ + +/** + * SECTION:element-osxvideosink + * + * The OSXVideoSink renders video frames to a MacOSX window. The video output + * must be directed to a window embedded in an existing NSApp. + * + * When the NSView to be embedded is created an element #GstMessage with a + * name of 'have-ns-view' will be created and posted on the bus. + * The pointer to the NSView to embed will be in the 'nsview' field of that + * message. The application MUST handle this message and embed the view + * appropriately. + */ + +#include "config.h" +#include <gst/interfaces/xoverlay.h> + +#include "osxvideosink.h" +#include <unistd.h> +#import "cocoawindow.h" + +GST_DEBUG_CATEGORY (gst_debug_osx_video_sink); +#define GST_CAT_DEFAULT gst_debug_osx_video_sink + +static GstStaticPadTemplate gst_osx_video_sink_sink_template_factory = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw-yuv, " + "framerate = (fraction) [ 0, MAX ], " + "width = (int) [ 1, MAX ], " + "height = (int) [ 1, MAX ], " +#if G_BYTE_ORDER == G_BIG_ENDIAN + "format = (fourcc) YUY2") +#else + "format = (fourcc) UYVY") +#endif + ); + +enum +{ + ARG_0, + ARG_EMBED, +}; + +static void gst_osx_video_sink_osxwindow_destroy (GstOSXVideoSink * osxvideosink); + +static GstVideoSinkClass *parent_class = NULL; + +/* This function handles osx window creation */ +static gboolean +gst_osx_video_sink_osxwindow_create (GstOSXVideoSink * osxvideosink, gint width, + gint height) +{ + NSRect rect; + GstOSXWindow *osxwindow = NULL; + GstStructure *s; + GstMessage *msg; + gboolean res = TRUE; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + g_return_val_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink), FALSE); + + GST_DEBUG_OBJECT (osxvideosink, "Creating new OSX window"); + + osxvideosink->osxwindow = osxwindow = g_new0 (GstOSXWindow, 1); + + osxwindow->width = width; + osxwindow->height = height; + + /* Allocate our GstGLView for the window, and then tell the application + * about it (hopefully it's listening...) */ + rect.origin.x = 0.0; + rect.origin.y = 0.0; + rect.size.width = (float) osxwindow->width; + rect.size.height = (float) osxwindow->height; + osxwindow->gstview =[[GstGLView alloc] initWithFrame:rect]; + + s = gst_structure_new ("have-ns-view", + "nsview", G_TYPE_POINTER, osxwindow->gstview, + nil); + + msg = gst_message_new_element (GST_OBJECT (osxvideosink), s); + gst_element_post_message (GST_ELEMENT (osxvideosink), msg); + + GST_INFO_OBJECT (osxvideosink, "'have-ns-view' message sent"); + + /* check if have-ns-view was handled and osxwindow->gstview was added to a + * superview + */ + if ([osxwindow->gstview haveSuperview] == NO) { + /* have-ns-view wasn't handled, post prepare-xwindow-id */ + if (osxvideosink->superview == NULL) { + GST_INFO_OBJECT (osxvideosink, "emitting prepare-xwindow-id"); + gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (osxvideosink)); + } + + if (osxvideosink->superview != NULL) { + /* prepare-xwindow-id was handled, we have the superview in + * osxvideosink->superview. We now add osxwindow->gstview to the superview + * from the main thread + */ + GST_INFO_OBJECT (osxvideosink, "we have a superview, adding our view to it"); + [osxwindow->gstview performSelectorOnMainThread:@selector(addToSuperview:) + withObject:osxvideosink->superview waitUntilDone:YES]; + } else { + /* the view wasn't added to a superview. It's possible that the + * application handled have-ns-view, stored our view internally and is + * going to add it to a superview later (webkit does that now). + */ + GST_INFO_OBJECT (osxvideosink, "no superview"); + } + } + + [pool release]; + + return res; +} + +static void +gst_osx_video_sink_osxwindow_destroy (GstOSXVideoSink * osxvideosink) +{ + NSAutoreleasePool *pool; + + g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink)); + pool = [[NSAutoreleasePool alloc] init]; + + if (osxvideosink->osxwindow) { + if (osxvideosink->superview) { + [osxvideosink->osxwindow->gstview + performSelectorOnMainThread:@selector(removeFromSuperview:) + withObject:(id)nil waitUntilDone:YES]; + } + [osxvideosink->osxwindow->gstview release]; + + g_free (osxvideosink->osxwindow); + osxvideosink->osxwindow = NULL; + } + [pool release]; +} + +/* This function resizes a GstXWindow */ +static void +gst_osx_video_sink_osxwindow_resize (GstOSXVideoSink * osxvideosink, + GstOSXWindow * osxwindow, guint width, guint height) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + g_return_if_fail (osxwindow != NULL); + g_return_if_fail (GST_IS_OSX_VIDEO_SINK (osxvideosink)); + + osxwindow->width = width; + osxwindow->height = height; + + GST_DEBUG_OBJECT (osxvideosink, "Resizing window to (%d,%d)", width, height); + + /* Directly resize the underlying view */ + GST_DEBUG_OBJECT (osxvideosink, "Calling setVideoSize on %p", osxwindow->gstview); + [osxwindow->gstview setVideoSize:width :height]; + + [pool release]; +} + +static gboolean +gst_osx_video_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) +{ + GstOSXVideoSink *osxvideosink; + GstStructure *structure; + gboolean res, result = FALSE; + gint video_width, video_height; + + osxvideosink = GST_OSX_VIDEO_SINK (bsink); + + GST_DEBUG_OBJECT (osxvideosink, "caps: %" GST_PTR_FORMAT, caps); + + structure = gst_caps_get_structure (caps, 0); + res = gst_structure_get_int (structure, "width", &video_width); + res &= gst_structure_get_int (structure, "height", &video_height); + + if (!res) { + goto beach; + } + + GST_DEBUG_OBJECT (osxvideosink, "our format is: %dx%d video", + video_width, video_height); + + GST_VIDEO_SINK_WIDTH (osxvideosink) = video_width; + GST_VIDEO_SINK_HEIGHT (osxvideosink) = video_height; + + gst_osx_video_sink_osxwindow_resize (osxvideosink, osxvideosink->osxwindow, + video_width, video_height); + result = TRUE; + +beach: + return result; + +} + +static GstStateChangeReturn +gst_osx_video_sink_change_state (GstElement * element, + GstStateChange transition) +{ + GstOSXVideoSink *osxvideosink; + GstStateChangeReturn ret; + + osxvideosink = GST_OSX_VIDEO_SINK (element); + + GST_DEBUG_OBJECT (osxvideosink, "%s => %s", + gst_element_state_get_name(GST_STATE_TRANSITION_CURRENT (transition)), + gst_element_state_get_name(GST_STATE_TRANSITION_NEXT (transition))); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + /* Creating our window and our image */ + GST_VIDEO_SINK_WIDTH (osxvideosink) = 320; + GST_VIDEO_SINK_HEIGHT (osxvideosink) = 240; + if (!gst_osx_video_sink_osxwindow_create (osxvideosink, + GST_VIDEO_SINK_WIDTH (osxvideosink), + GST_VIDEO_SINK_HEIGHT (osxvideosink))) { + ret = GST_STATE_CHANGE_FAILURE; + goto done; + } + break; + default: + break; + } + + ret = (GST_ELEMENT_CLASS (parent_class))->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + GST_VIDEO_SINK_WIDTH (osxvideosink) = 0; + GST_VIDEO_SINK_HEIGHT (osxvideosink) = 0; + gst_osx_video_sink_osxwindow_destroy (osxvideosink); + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + +done: + return ret; +} + +static GstFlowReturn +gst_osx_video_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf) +{ + GstOSXVideoSink *osxvideosink; + guint8 *viewdata; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + osxvideosink = GST_OSX_VIDEO_SINK (bsink); + viewdata = (guint8 *) [osxvideosink->osxwindow->gstview getTextureBuffer]; + + GST_DEBUG ("show_frame"); + memcpy (viewdata, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + [osxvideosink->osxwindow->gstview displayTexture]; + + [pool release]; + + return GST_FLOW_OK; +} + +/* Buffer management */ + + + +/* =========================================== */ +/* */ +/* Init & Class init */ +/* */ +/* =========================================== */ + +static void +gst_osx_video_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOSXVideoSink *osxvideosink; + + g_return_if_fail (GST_IS_OSX_VIDEO_SINK (object)); + + osxvideosink = GST_OSX_VIDEO_SINK (object); + + switch (prop_id) { + case ARG_EMBED: + /* Ignore, just here for backwards compatibility */ + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_osx_video_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstOSXVideoSink *osxvideosink; + + g_return_if_fail (GST_IS_OSX_VIDEO_SINK (object)); + + osxvideosink = GST_OSX_VIDEO_SINK (object); + + switch (prop_id) { + case ARG_EMBED: + g_value_set_boolean (value, TRUE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static void +gst_osx_video_sink_init (GstOSXVideoSink * osxvideosink) +{ + osxvideosink->osxwindow = NULL; + osxvideosink->superview = NULL; +} + +static void +gst_osx_video_sink_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details_simple (element_class, "OSX Video sink", + "Sink/Video", "OSX native videosink", + "Zaheer Abbas Merali <zaheerabbas at merali dot org>"); + + gst_element_class_add_static_pad_template (element_class, + &gst_osx_video_sink_sink_template_factory); +} + +static void +gst_osx_video_sink_finalize (GObject *object) +{ + GstOSXVideoSink *osxvideosink = GST_OSX_VIDEO_SINK (object); + + if (osxvideosink->superview) + [osxvideosink->superview release]; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_osx_video_sink_class_init (GstOSXVideoSinkClass * 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_ref (GST_TYPE_VIDEO_SINK); + + gobject_class->set_property = gst_osx_video_sink_set_property; + gobject_class->get_property = gst_osx_video_sink_get_property; + gobject_class->finalize = gst_osx_video_sink_finalize; + + gstbasesink_class->set_caps = gst_osx_video_sink_setcaps; + gstbasesink_class->preroll = gst_osx_video_sink_show_frame; + gstbasesink_class->render = gst_osx_video_sink_show_frame; + gstelement_class->change_state = gst_osx_video_sink_change_state; + + /** + * GstOSXVideoSink:embed + * + * Set to #TRUE if you are embedding the video window in an application. + * + **/ + + g_object_class_install_property (gobject_class, ARG_EMBED, + g_param_spec_boolean ("embed", "embed", "For ABI compatiblity only, do not use", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +static gboolean +gst_osx_video_sink_interface_supported (GstImplementsInterface * iface, GType type) +{ + g_assert (type == GST_TYPE_X_OVERLAY); + return TRUE; +} + +static void +gst_osx_video_sink_interface_init (GstImplementsInterfaceClass * klass) +{ + klass->supported = gst_osx_video_sink_interface_supported; +} + +static void +gst_osx_video_sink_set_window_handle (GstXOverlay * overlay, guintptr handle_id) +{ + GstOSXVideoSink *osxvideosink = GST_OSX_VIDEO_SINK (overlay); + gulong window_id = (gulong) handle_id; + + if (osxvideosink->superview) { + GST_INFO_OBJECT (osxvideosink, "old xwindow id %p", osxvideosink->superview); + if (osxvideosink->osxwindow) { + [osxvideosink->osxwindow->gstview + performSelectorOnMainThread:@selector(removeFromSuperview:) + withObject:(id)nil waitUntilDone:YES]; + } + [osxvideosink->superview release]; + } + + GST_INFO_OBJECT (osxvideosink, "set xwindow id 0x%lx", window_id); + osxvideosink->superview = [((NSView *) window_id) retain]; + if (osxvideosink->osxwindow) { + [osxvideosink->osxwindow->gstview performSelectorOnMainThread:@selector(addToSuperview:) + withObject:osxvideosink->superview waitUntilDone:YES]; + } +} + +static void +gst_osx_video_sink_xoverlay_init (GstXOverlayClass * iface) +{ + iface->set_window_handle = gst_osx_video_sink_set_window_handle; + iface->expose = NULL; + iface->handle_events = NULL; +} + +/* ============================================================= */ +/* */ +/* Public Methods */ +/* */ +/* ============================================================= */ + +/* =========================================== */ +/* */ +/* Object typing & Creation */ +/* */ +/* =========================================== */ + +GType +gst_osx_video_sink_get_type (void) +{ + static GType osxvideosink_type = 0; + + if (!osxvideosink_type) { + static const GTypeInfo osxvideosink_info = { + sizeof (GstOSXVideoSinkClass), + gst_osx_video_sink_base_init, + NULL, + (GClassInitFunc) gst_osx_video_sink_class_init, + NULL, + NULL, + sizeof (GstOSXVideoSink), + 0, + (GInstanceInitFunc) gst_osx_video_sink_init, + }; + + static const GInterfaceInfo iface_info = { + (GInterfaceInitFunc) gst_osx_video_sink_interface_init, + NULL, + NULL, + }; + + static const GInterfaceInfo overlay_info = { + (GInterfaceInitFunc) gst_osx_video_sink_xoverlay_init, + NULL, + NULL, + }; + + osxvideosink_type = g_type_register_static (GST_TYPE_VIDEO_SINK, + "GstOSXVideoSink", &osxvideosink_info, 0); + + g_type_add_interface_static (osxvideosink_type, + GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info); + g_type_add_interface_static (osxvideosink_type, GST_TYPE_X_OVERLAY, + &overlay_info); + } + + return osxvideosink_type; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + + if (!gst_element_register (plugin, "osxvideosink", + GST_RANK_PRIMARY, GST_TYPE_OSX_VIDEO_SINK)) + return FALSE; + + GST_DEBUG_CATEGORY_INIT (gst_debug_osx_video_sink, "osxvideosink", 0, + "osxvideosink element"); + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "osxvideo", + "OSX native video output plugin", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/sunaudio/Makefile.am b/sys/sunaudio/Makefile.am new file mode 100644 index 0000000..e106ce3 --- /dev/null +++ b/sys/sunaudio/Makefile.am @@ -0,0 +1,26 @@ +plugin_LTLIBRARIES = libgstsunaudio.la + +libgstsunaudio_la_SOURCES = gstsunaudio.c \ + gstsunaudiosink.c \ + gstsunaudiomixerctrl.c \ + gstsunaudiomixer.c \ + gstsunaudiomixertrack.c \ + gstsunaudiomixeroptions.c \ + gstsunaudiosrc.c + +libgstsunaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstsunaudio_la_LIBADD = \ + -lgstinterfaces-@GST_MAJORMINOR@ \ + -lgstaudio-@GST_MAJORMINOR@ \ + $(GST_PLUGINS_BASE_LIBS) \ + $(GST_LIBS) +libgstsunaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstsunaudio_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstsunaudiosink.h \ + gstsunaudiomixer.h \ + gstsunaudiomixerctrl.h \ + gstsunaudiomixertrack.h \ + gstsunaudiomixeroptions.h \ + gstsunaudiosrc.h + diff --git a/sys/sunaudio/Makefile.in b/sys/sunaudio/Makefile.in new file mode 100644 index 0000000..a1d1abd --- /dev/null +++ b/sys/sunaudio/Makefile.in @@ -0,0 +1,877 @@ +# 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 = sys/sunaudio +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 = +libgstsunaudio_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_libgstsunaudio_la_OBJECTS = libgstsunaudio_la-gstsunaudio.lo \ + libgstsunaudio_la-gstsunaudiosink.lo \ + libgstsunaudio_la-gstsunaudiomixerctrl.lo \ + libgstsunaudio_la-gstsunaudiomixer.lo \ + libgstsunaudio_la-gstsunaudiomixertrack.lo \ + libgstsunaudio_la-gstsunaudiomixeroptions.lo \ + libgstsunaudio_la-gstsunaudiosrc.lo +libgstsunaudio_la_OBJECTS = $(am_libgstsunaudio_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +libgstsunaudio_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) \ + $(libgstsunaudio_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 = $(libgstsunaudio_la_SOURCES) +DIST_SOURCES = $(libgstsunaudio_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 = libgstsunaudio.la +libgstsunaudio_la_SOURCES = gstsunaudio.c \ + gstsunaudiosink.c \ + gstsunaudiomixerctrl.c \ + gstsunaudiomixer.c \ + gstsunaudiomixertrack.c \ + gstsunaudiomixeroptions.c \ + gstsunaudiosrc.c + +libgstsunaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstsunaudio_la_LIBADD = \ + -lgstinterfaces-@GST_MAJORMINOR@ \ + -lgstaudio-@GST_MAJORMINOR@ \ + $(GST_PLUGINS_BASE_LIBS) \ + $(GST_LIBS) + +libgstsunaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstsunaudio_la_LIBTOOLFLAGS = --tag=disable-static +noinst_HEADERS = gstsunaudiosink.h \ + gstsunaudiomixer.h \ + gstsunaudiomixerctrl.h \ + gstsunaudiomixertrack.h \ + gstsunaudiomixeroptions.h \ + gstsunaudiosrc.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 sys/sunaudio/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu sys/sunaudio/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 +libgstsunaudio.la: $(libgstsunaudio_la_OBJECTS) $(libgstsunaudio_la_DEPENDENCIES) $(EXTRA_libgstsunaudio_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgstsunaudio_la_LINK) -rpath $(plugindir) $(libgstsunaudio_la_OBJECTS) $(libgstsunaudio_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstsunaudio_la-gstsunaudio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstsunaudio_la-gstsunaudiomixer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstsunaudio_la-gstsunaudiomixerctrl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstsunaudio_la-gstsunaudiomixeroptions.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstsunaudio_la-gstsunaudiomixertrack.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstsunaudio_la-gstsunaudiosink.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstsunaudio_la-gstsunaudiosrc.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 $@ $< + +libgstsunaudio_la-gstsunaudio.lo: gstsunaudio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -MT libgstsunaudio_la-gstsunaudio.lo -MD -MP -MF $(DEPDIR)/libgstsunaudio_la-gstsunaudio.Tpo -c -o libgstsunaudio_la-gstsunaudio.lo `test -f 'gstsunaudio.c' || echo '$(srcdir)/'`gstsunaudio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstsunaudio_la-gstsunaudio.Tpo $(DEPDIR)/libgstsunaudio_la-gstsunaudio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsunaudio.c' object='libgstsunaudio_la-gstsunaudio.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 $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -c -o libgstsunaudio_la-gstsunaudio.lo `test -f 'gstsunaudio.c' || echo '$(srcdir)/'`gstsunaudio.c + +libgstsunaudio_la-gstsunaudiosink.lo: gstsunaudiosink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -MT libgstsunaudio_la-gstsunaudiosink.lo -MD -MP -MF $(DEPDIR)/libgstsunaudio_la-gstsunaudiosink.Tpo -c -o libgstsunaudio_la-gstsunaudiosink.lo `test -f 'gstsunaudiosink.c' || echo '$(srcdir)/'`gstsunaudiosink.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstsunaudio_la-gstsunaudiosink.Tpo $(DEPDIR)/libgstsunaudio_la-gstsunaudiosink.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsunaudiosink.c' object='libgstsunaudio_la-gstsunaudiosink.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 $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -c -o libgstsunaudio_la-gstsunaudiosink.lo `test -f 'gstsunaudiosink.c' || echo '$(srcdir)/'`gstsunaudiosink.c + +libgstsunaudio_la-gstsunaudiomixerctrl.lo: gstsunaudiomixerctrl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -MT libgstsunaudio_la-gstsunaudiomixerctrl.lo -MD -MP -MF $(DEPDIR)/libgstsunaudio_la-gstsunaudiomixerctrl.Tpo -c -o libgstsunaudio_la-gstsunaudiomixerctrl.lo `test -f 'gstsunaudiomixerctrl.c' || echo '$(srcdir)/'`gstsunaudiomixerctrl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstsunaudio_la-gstsunaudiomixerctrl.Tpo $(DEPDIR)/libgstsunaudio_la-gstsunaudiomixerctrl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsunaudiomixerctrl.c' object='libgstsunaudio_la-gstsunaudiomixerctrl.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 $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -c -o libgstsunaudio_la-gstsunaudiomixerctrl.lo `test -f 'gstsunaudiomixerctrl.c' || echo '$(srcdir)/'`gstsunaudiomixerctrl.c + +libgstsunaudio_la-gstsunaudiomixer.lo: gstsunaudiomixer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -MT libgstsunaudio_la-gstsunaudiomixer.lo -MD -MP -MF $(DEPDIR)/libgstsunaudio_la-gstsunaudiomixer.Tpo -c -o libgstsunaudio_la-gstsunaudiomixer.lo `test -f 'gstsunaudiomixer.c' || echo '$(srcdir)/'`gstsunaudiomixer.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstsunaudio_la-gstsunaudiomixer.Tpo $(DEPDIR)/libgstsunaudio_la-gstsunaudiomixer.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsunaudiomixer.c' object='libgstsunaudio_la-gstsunaudiomixer.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 $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -c -o libgstsunaudio_la-gstsunaudiomixer.lo `test -f 'gstsunaudiomixer.c' || echo '$(srcdir)/'`gstsunaudiomixer.c + +libgstsunaudio_la-gstsunaudiomixertrack.lo: gstsunaudiomixertrack.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -MT libgstsunaudio_la-gstsunaudiomixertrack.lo -MD -MP -MF $(DEPDIR)/libgstsunaudio_la-gstsunaudiomixertrack.Tpo -c -o libgstsunaudio_la-gstsunaudiomixertrack.lo `test -f 'gstsunaudiomixertrack.c' || echo '$(srcdir)/'`gstsunaudiomixertrack.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstsunaudio_la-gstsunaudiomixertrack.Tpo $(DEPDIR)/libgstsunaudio_la-gstsunaudiomixertrack.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsunaudiomixertrack.c' object='libgstsunaudio_la-gstsunaudiomixertrack.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 $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -c -o libgstsunaudio_la-gstsunaudiomixertrack.lo `test -f 'gstsunaudiomixertrack.c' || echo '$(srcdir)/'`gstsunaudiomixertrack.c + +libgstsunaudio_la-gstsunaudiomixeroptions.lo: gstsunaudiomixeroptions.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -MT libgstsunaudio_la-gstsunaudiomixeroptions.lo -MD -MP -MF $(DEPDIR)/libgstsunaudio_la-gstsunaudiomixeroptions.Tpo -c -o libgstsunaudio_la-gstsunaudiomixeroptions.lo `test -f 'gstsunaudiomixeroptions.c' || echo '$(srcdir)/'`gstsunaudiomixeroptions.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstsunaudio_la-gstsunaudiomixeroptions.Tpo $(DEPDIR)/libgstsunaudio_la-gstsunaudiomixeroptions.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsunaudiomixeroptions.c' object='libgstsunaudio_la-gstsunaudiomixeroptions.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 $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -c -o libgstsunaudio_la-gstsunaudiomixeroptions.lo `test -f 'gstsunaudiomixeroptions.c' || echo '$(srcdir)/'`gstsunaudiomixeroptions.c + +libgstsunaudio_la-gstsunaudiosrc.lo: gstsunaudiosrc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -MT libgstsunaudio_la-gstsunaudiosrc.lo -MD -MP -MF $(DEPDIR)/libgstsunaudio_la-gstsunaudiosrc.Tpo -c -o libgstsunaudio_la-gstsunaudiosrc.lo `test -f 'gstsunaudiosrc.c' || echo '$(srcdir)/'`gstsunaudiosrc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstsunaudio_la-gstsunaudiosrc.Tpo $(DEPDIR)/libgstsunaudio_la-gstsunaudiosrc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstsunaudiosrc.c' object='libgstsunaudio_la-gstsunaudiosrc.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 $(libgstsunaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstsunaudio_la_CFLAGS) $(CFLAGS) -c -o libgstsunaudio_la-gstsunaudiosrc.lo `test -f 'gstsunaudiosrc.c' || echo '$(srcdir)/'`gstsunaudiosrc.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/sys/sunaudio/gstsunaudio.c b/sys/sunaudio/gstsunaudio.c new file mode 100644 index 0000000..07aa575 --- /dev/null +++ b/sys/sunaudio/gstsunaudio.c @@ -0,0 +1,63 @@ +/* + * GStreamer - SunAudio plugin + * Copyright (C) 2005,2006 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.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 "gst/gst-i18n-plugin.h" + +#include "gstsunaudiomixer.h" +#include "gstsunaudiosink.h" +#include "gstsunaudiosrc.h" + +extern gchar *__gst_oss_plugin_dir; + +GST_DEBUG_CATEGORY (sunaudio_debug); + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "sunaudiomixer", GST_RANK_NONE, + GST_TYPE_SUNAUDIO_MIXER) || + !gst_element_register (plugin, "sunaudiosink", GST_RANK_SECONDARY, + GST_TYPE_SUNAUDIO_SINK) || + !gst_element_register (plugin, "sunaudiosrc", GST_RANK_SECONDARY, + GST_TYPE_SUNAUDIO_SRC)) { + return FALSE; + } + + GST_DEBUG_CATEGORY_INIT (sunaudio_debug, "sunaudio", 0, "sunaudio 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, + "sunaudio", + "Sun Audio support for GStreamer", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/sunaudio/gstsunaudiomixer.c b/sys/sunaudio/gstsunaudiomixer.c new file mode 100644 index 0000000..7688450 --- /dev/null +++ b/sys/sunaudio/gstsunaudiomixer.c @@ -0,0 +1,104 @@ +/* + * GStreamer - SunAudio mixer + * Copyright (C) 2005,2006 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.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-sunaudiomixer + * + * sunaudiomixer is an mixer that controls the sound input and output + * levels with the Sun Audio interface available in Solaris. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstsunaudiomixer.h" + +GST_BOILERPLATE_WITH_INTERFACE (GstSunAudioMixer, gst_sunaudiomixer, + GstElement, GST_TYPE_ELEMENT, GstMixer, GST_TYPE_MIXER, gst_sunaudiomixer); + +GST_IMPLEMENT_SUNAUDIO_MIXER_CTRL_METHODS (GstSunAudioMixer, gst_sunaudiomixer); + +static GstStateChangeReturn gst_sunaudiomixer_change_state (GstElement * + element, GstStateChange transition); + +static void +gst_sunaudiomixer_base_init (gpointer klass) +{ + gst_element_class_set_details_simple (GST_ELEMENT_CLASS (klass), + "Sun Audio Mixer", "Generic/Audio", + "Control sound input and output levels with Sun Audio", + "Brian Cameron <brian.cameron@sun.com>"); +} + +static void +gst_sunaudiomixer_class_init (GstSunAudioMixerClass * klass) +{ + GstElementClass *element_class; + + element_class = (GstElementClass *) klass; + + element_class->change_state = gst_sunaudiomixer_change_state; +} + +static void +gst_sunaudiomixer_init (GstSunAudioMixer * this, + GstSunAudioMixerClass * g_class) +{ + this->mixer = NULL; +} + +static GstStateChangeReturn +gst_sunaudiomixer_change_state (GstElement * element, GstStateChange transition) +{ + GstSunAudioMixer *this = GST_SUNAUDIO_MIXER (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!this->mixer) { + const char *audiodev; + + audiodev = g_getenv ("AUDIODEV"); + if (audiodev == NULL) { + this->mixer = gst_sunaudiomixer_ctrl_new ("/dev/audioctl"); + } else { + gchar *device = g_strdup_printf ("%sctl", audiodev); + + this->mixer = gst_sunaudiomixer_ctrl_new (device); + g_free (device); + } + } + break; + case GST_STATE_CHANGE_READY_TO_NULL: + if (this->mixer) { + gst_sunaudiomixer_ctrl_free (this->mixer); + this->mixer = NULL; + } + break; + default: + break; + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + return GST_STATE_CHANGE_SUCCESS; +} diff --git a/sys/sunaudio/gstsunaudiomixer.h b/sys/sunaudio/gstsunaudiomixer.h new file mode 100644 index 0000000..7ab6e74 --- /dev/null +++ b/sys/sunaudio/gstsunaudiomixer.h @@ -0,0 +1,51 @@ +/* + * GStreamer - SunAudio mixer + * Copyright (C) 2005,2006 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __GST_SUNAUDIO_MIXER_H__ +#define __GST_SUNAUDIO_MIXER_H__ + +#include "gstsunaudiomixerctrl.h" + +G_BEGIN_DECLS + +#define GST_SUNAUDIO_MIXER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SUNAUDIO_MIXER,GstSunAudioMixer)) +#define GST_SUNAUDIO_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SUNAUDIO_MIXER,GstSunAudioMixerClass)) +#define GST_IS_SUNAUDIO_MIXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SUNAUDIO_MIXER)) +#define GST_IS_SUNAUDIO_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SUNAUDIO_MIXER)) +#define GST_TYPE_SUNAUDIO_MIXER (gst_sunaudiomixer_get_type()) + +typedef struct _GstSunAudioMixer GstSunAudioMixer; +typedef struct _GstSunAudioMixerClass GstSunAudioMixerClass; + +struct _GstSunAudioMixer { + GstElement parent; + + GstSunAudioMixerCtrl *mixer; +}; + +struct _GstSunAudioMixerClass { + GstElementClass parent; +}; + +GType gst_sunaudiomixer_get_type (void); + +G_END_DECLS + +#endif /* __GST_SUNAUDIO_MIXER_H__ */ diff --git a/sys/sunaudio/gstsunaudiomixerctrl.c b/sys/sunaudio/gstsunaudiomixerctrl.c new file mode 100644 index 0000000..0723134 --- /dev/null +++ b/sys/sunaudio/gstsunaudiomixerctrl.c @@ -0,0 +1,585 @@ +/* + * GStreamer - SunAudio mixer interface element + * Copyright (C) 2005,2006,2008,2009 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.com> + * Copyright (C) 2008 Sun Microsystems, Inc., + * Jan Schmidt <jan.schmidt@sun.com> + * Copyright (C) 2009 Sun Microsystems, Inc., + * Garrett D'Amore <garrett.damore@sun.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 <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/audio.h> +#include <sys/mixer.h> + +#include <gst/gst-i18n-plugin.h> + +#include "gstsunaudiomixerctrl.h" +#include "gstsunaudiomixertrack.h" +#include "gstsunaudiomixeroptions.h" + +GST_DEBUG_CATEGORY_EXTERN (sunaudio_debug); +#define GST_CAT_DEFAULT sunaudio_debug + +static gboolean +gst_sunaudiomixer_ctrl_open (GstSunAudioMixerCtrl * mixer) +{ + int fd; + + /* First try to open non-blocking */ + fd = open (mixer->device, O_RDWR | O_NONBLOCK); + + if (fd >= 0) { + close (fd); + fd = open (mixer->device, O_WRONLY); + } + + if (fd == -1) { + GST_DEBUG_OBJECT (mixer, + "Failed to open mixer device %s, mixing disabled: %s", mixer->device, + strerror (errno)); + + return FALSE; + } + mixer->mixer_fd = fd; + + /* Try to set the multiple open flag if we can, but ignore errors */ + ioctl (mixer->mixer_fd, AUDIO_MIXER_MULTIPLE_OPEN); + + GST_DEBUG_OBJECT (mixer, "Opened mixer device %s", mixer->device); + + return TRUE; +} + +void +gst_sunaudiomixer_ctrl_build_list (GstSunAudioMixerCtrl * mixer) +{ + GstMixerTrack *track; + GstMixerOptions *options; + + struct audio_info audioinfo; + + /* + * Do not continue appending the same 3 static tracks onto the list + */ + if (mixer->tracklist == NULL) { + g_return_if_fail (mixer->mixer_fd != -1); + + /* query available ports */ + if (ioctl (mixer->mixer_fd, AUDIO_GETINFO, &audioinfo) < 0) { + g_warning ("Error getting audio device volume"); + return; + } + + /* Output & should be MASTER when it's the only one. */ + track = gst_sunaudiomixer_track_new (GST_SUNAUDIO_TRACK_OUTPUT); + mixer->tracklist = g_list_append (mixer->tracklist, track); + + /* Input */ + track = gst_sunaudiomixer_track_new (GST_SUNAUDIO_TRACK_RECORD); + mixer->tracklist = g_list_append (mixer->tracklist, track); + + /* Monitor */ + track = gst_sunaudiomixer_track_new (GST_SUNAUDIO_TRACK_MONITOR); + mixer->tracklist = g_list_append (mixer->tracklist, track); + + if (audioinfo.play.avail_ports & AUDIO_SPEAKER) { + track = gst_sunaudiomixer_track_new (GST_SUNAUDIO_TRACK_SPEAKER); + mixer->tracklist = g_list_append (mixer->tracklist, track); + } + if (audioinfo.play.avail_ports & AUDIO_HEADPHONE) { + track = gst_sunaudiomixer_track_new (GST_SUNAUDIO_TRACK_HP); + mixer->tracklist = g_list_append (mixer->tracklist, track); + } + if (audioinfo.play.avail_ports & AUDIO_LINE_OUT) { + track = gst_sunaudiomixer_track_new (GST_SUNAUDIO_TRACK_LINEOUT); + mixer->tracklist = g_list_append (mixer->tracklist, track); + } + if (audioinfo.play.avail_ports & AUDIO_SPDIF_OUT) { + track = gst_sunaudiomixer_track_new (GST_SUNAUDIO_TRACK_SPDIFOUT); + mixer->tracklist = g_list_append (mixer->tracklist, track); + } + if (audioinfo.play.avail_ports & AUDIO_AUX1_OUT) { + track = gst_sunaudiomixer_track_new (GST_SUNAUDIO_TRACK_AUX1OUT); + mixer->tracklist = g_list_append (mixer->tracklist, track); + } + if (audioinfo.play.avail_ports & AUDIO_AUX2_OUT) { + track = gst_sunaudiomixer_track_new (GST_SUNAUDIO_TRACK_AUX2OUT); + mixer->tracklist = g_list_append (mixer->tracklist, track); + } + + if (audioinfo.record.avail_ports != AUDIO_NONE) { + options = + gst_sunaudiomixer_options_new (mixer, GST_SUNAUDIO_TRACK_RECSRC); + mixer->tracklist = g_list_append (mixer->tracklist, options); + } + } +} + +GstSunAudioMixerCtrl * +gst_sunaudiomixer_ctrl_new (const char *device) +{ + GstSunAudioMixerCtrl *ret = NULL; + + g_return_val_if_fail (device != NULL, NULL); + + ret = g_new0 (GstSunAudioMixerCtrl, 1); + + ret->device = g_strdup (device); + ret->mixer_fd = -1; + ret->tracklist = NULL; + + if (!gst_sunaudiomixer_ctrl_open (ret)) + goto error; + + return ret; + +error: + if (ret) + gst_sunaudiomixer_ctrl_free (ret); + + return NULL; +} + +void +gst_sunaudiomixer_ctrl_free (GstSunAudioMixerCtrl * mixer) +{ + g_return_if_fail (mixer != NULL); + + if (mixer->device) { + g_free (mixer->device); + mixer->device = NULL; + } + + if (mixer->tracklist) { + g_list_foreach (mixer->tracklist, (GFunc) g_object_unref, NULL); + g_list_free (mixer->tracklist); + mixer->tracklist = NULL; + } + + if (mixer->mixer_fd != -1) { + close (mixer->mixer_fd); + mixer->mixer_fd = -1; + } + + g_free (mixer); +} + +GstMixerFlags +gst_sunaudiomixer_ctrl_get_mixer_flags (GstSunAudioMixerCtrl * mixer) +{ + return GST_MIXER_FLAG_HAS_WHITELIST | GST_MIXER_FLAG_GROUPING; +} + +const GList * +gst_sunaudiomixer_ctrl_list_tracks (GstSunAudioMixerCtrl * mixer) +{ + gst_sunaudiomixer_ctrl_build_list (mixer); + + return (const GList *) mixer->tracklist; +} + +void +gst_sunaudiomixer_ctrl_get_volume (GstSunAudioMixerCtrl * mixer, + GstMixerTrack * track, gint * volumes) +{ + gint gain, balance; + float ratio; + struct audio_info audioinfo; + GstSunAudioMixerTrack *sunaudiotrack; + + g_return_if_fail (GST_IS_SUNAUDIO_MIXER_TRACK (track)); + sunaudiotrack = GST_SUNAUDIO_MIXER_TRACK (track); + + g_return_if_fail (mixer->mixer_fd != -1); + + if (ioctl (mixer->mixer_fd, AUDIO_GETINFO, &audioinfo) < 0) { + g_warning ("Error getting audio device volume"); + return; + } + + balance = AUDIO_MID_BALANCE; + gain = 0; + + switch (sunaudiotrack->track_num) { + case GST_SUNAUDIO_TRACK_OUTPUT: + gain = (int) audioinfo.play.gain; + balance = audioinfo.play.balance; + break; + case GST_SUNAUDIO_TRACK_RECORD: + gain = (int) audioinfo.record.gain; + balance = audioinfo.record.balance; + break; + case GST_SUNAUDIO_TRACK_MONITOR: + gain = (int) audioinfo.monitor_gain; + balance = audioinfo.record.balance; + break; + case GST_SUNAUDIO_TRACK_SPEAKER: + if (audioinfo.play.port & AUDIO_SPEAKER) + gain = AUDIO_MAX_GAIN; + break; + case GST_SUNAUDIO_TRACK_HP: + if (audioinfo.play.port & AUDIO_HEADPHONE) + gain = AUDIO_MAX_GAIN; + break; + case GST_SUNAUDIO_TRACK_LINEOUT: + if (audioinfo.play.port & AUDIO_LINE_OUT) + gain = AUDIO_MAX_GAIN; + break; + case GST_SUNAUDIO_TRACK_SPDIFOUT: + if (audioinfo.play.port & AUDIO_SPDIF_OUT) + gain = AUDIO_MAX_GAIN; + break; + case GST_SUNAUDIO_TRACK_AUX1OUT: + if (audioinfo.play.port & AUDIO_AUX1_OUT) + gain = AUDIO_MAX_GAIN; + break; + case GST_SUNAUDIO_TRACK_AUX2OUT: + if (audioinfo.play.port & AUDIO_AUX2_OUT) + gain = AUDIO_MAX_GAIN; + break; + default: + break; + } + + switch (track->num_channels) { + case 2: + if (balance == AUDIO_MID_BALANCE) { + volumes[0] = gain; + volumes[1] = gain; + } else if (balance < AUDIO_MID_BALANCE) { + volumes[0] = gain; + ratio = 1 - (float) (AUDIO_MID_BALANCE - balance) / + (float) AUDIO_MID_BALANCE; + volumes[1] = (int) ((float) gain * ratio + 0.5); + } else { + volumes[1] = gain; + ratio = 1 - (float) (balance - AUDIO_MID_BALANCE) / + (float) AUDIO_MID_BALANCE; + volumes[0] = (int) ((float) gain * ratio + 0.5); + } + break; + case 1: + volumes[0] = gain; + break; + } + + /* Likewise reset MUTE */ + if ((sunaudiotrack->track_num == GST_SUNAUDIO_TRACK_OUTPUT + && audioinfo.output_muted == 1) + || (sunaudiotrack->track_num != GST_SUNAUDIO_TRACK_OUTPUT && gain == 0)) { + /* + * If MUTE is set, then gain is always 0, so don't bother + * resetting our internal value. + */ + track->flags |= GST_MIXER_TRACK_MUTE; + } else { + sunaudiotrack->gain = gain; + sunaudiotrack->balance = balance; + track->flags &= ~GST_MIXER_TRACK_MUTE; + } +} + +void +gst_sunaudiomixer_ctrl_set_volume (GstSunAudioMixerCtrl * mixer, + GstMixerTrack * track, gint * volumes) +{ + gint gain; + gint balance; + gint l_real_gain; + gint r_real_gain; + float ratio; + struct audio_info audioinfo; + GstSunAudioMixerTrack *sunaudiotrack = GST_SUNAUDIO_MIXER_TRACK (track); + + l_real_gain = volumes[0]; + r_real_gain = volumes[1]; + + if (l_real_gain == r_real_gain) { + gain = l_real_gain; + balance = AUDIO_MID_BALANCE; + } else if (l_real_gain < r_real_gain) { + gain = r_real_gain; + ratio = (float) l_real_gain / (float) r_real_gain; + balance = + AUDIO_RIGHT_BALANCE - (int) (ratio * (float) AUDIO_MID_BALANCE + 0.5); + } else { + gain = l_real_gain; + ratio = (float) r_real_gain / (float) l_real_gain; + balance = + AUDIO_LEFT_BALANCE + (int) (ratio * (float) AUDIO_MID_BALANCE + 0.5); + } + + sunaudiotrack->gain = gain; + sunaudiotrack->balance = balance; + + if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE)) { + if (sunaudiotrack->track_num == GST_SUNAUDIO_TRACK_OUTPUT) { + return; + } else if (gain == 0) { + return; + } else { + /* + * If the volume is set to a non-zero value for LINE_IN + * or MONITOR, then unset MUTE. + */ + track->flags &= ~GST_MIXER_TRACK_MUTE; + } + } + + /* Set the volume */ + AUDIO_INITINFO (&audioinfo); + + switch (sunaudiotrack->track_num) { + case GST_SUNAUDIO_TRACK_OUTPUT: + audioinfo.play.gain = gain; + audioinfo.play.balance = balance; + break; + case GST_SUNAUDIO_TRACK_RECORD: + audioinfo.record.gain = gain; + audioinfo.record.balance = balance; + break; + case GST_SUNAUDIO_TRACK_MONITOR: + audioinfo.monitor_gain = gain; + audioinfo.record.balance = balance; + break; + default: + break; + } + + g_return_if_fail (mixer->mixer_fd != -1); + + if (ioctl (mixer->mixer_fd, AUDIO_SETINFO, &audioinfo) < 0) { + g_warning ("Error setting audio device volume"); + return; + } +} + +void +gst_sunaudiomixer_ctrl_set_mute (GstSunAudioMixerCtrl * mixer, + GstMixerTrack * track, gboolean mute) +{ + struct audio_info audioinfo; + struct audio_info oldinfo; + GstSunAudioMixerTrack *sunaudiotrack = GST_SUNAUDIO_MIXER_TRACK (track); + gint volume, balance; + + AUDIO_INITINFO (&audioinfo); + + if (ioctl (mixer->mixer_fd, AUDIO_GETINFO, &oldinfo) < 0) { + g_warning ("Error getting audio device volume"); + return; + } + + if (mute) { + volume = 0; + track->flags |= GST_MIXER_TRACK_MUTE; + } else { + volume = sunaudiotrack->gain; + track->flags &= ~GST_MIXER_TRACK_MUTE; + } + + balance = sunaudiotrack->balance; + + switch (sunaudiotrack->track_num) { + case GST_SUNAUDIO_TRACK_OUTPUT: + if (mute) + audioinfo.output_muted = 1; + else + audioinfo.output_muted = 0; + + audioinfo.play.gain = volume; + audioinfo.play.balance = balance; + break; + case GST_SUNAUDIO_TRACK_RECORD: + audioinfo.record.gain = volume; + audioinfo.record.balance = balance; + break; + case GST_SUNAUDIO_TRACK_MONITOR: + audioinfo.monitor_gain = volume; + audioinfo.record.balance = balance; + break; + case GST_SUNAUDIO_TRACK_SPEAKER: + if (mute) { + audioinfo.play.port = oldinfo.play.port & ~AUDIO_SPEAKER; + } else { + audioinfo.play.port = oldinfo.play.port | AUDIO_SPEAKER; + } + break; + case GST_SUNAUDIO_TRACK_HP: + if (mute) { + audioinfo.play.port = oldinfo.play.port & ~AUDIO_HEADPHONE; + } else { + audioinfo.play.port = oldinfo.play.port | AUDIO_HEADPHONE; + } + break; + case GST_SUNAUDIO_TRACK_LINEOUT: + if (mute) { + audioinfo.play.port = oldinfo.play.port & ~AUDIO_LINE_OUT; + } else { + audioinfo.play.port = oldinfo.play.port | AUDIO_LINE_OUT; + } + break; + case GST_SUNAUDIO_TRACK_SPDIFOUT: + if (mute) { + audioinfo.play.port = oldinfo.play.port & ~AUDIO_SPDIF_OUT; + } else { + audioinfo.play.port = oldinfo.play.port | AUDIO_SPDIF_OUT; + } + break; + case GST_SUNAUDIO_TRACK_AUX1OUT: + if (mute) { + audioinfo.play.port = oldinfo.play.port & ~AUDIO_AUX1_OUT; + } else { + audioinfo.play.port = oldinfo.play.port | AUDIO_AUX1_OUT; + } + break; + case GST_SUNAUDIO_TRACK_AUX2OUT: + if (mute) { + audioinfo.play.port = oldinfo.play.port & ~AUDIO_AUX2_OUT; + } else { + audioinfo.play.port = oldinfo.play.port | AUDIO_AUX2_OUT; + } + break; + default: + break; + } + + if (audioinfo.play.port != ((unsigned) ~0)) { + /* mask off ports we can't modify. Hack for broken drivers where mod_ports == 0 */ + if (oldinfo.play.mod_ports != 0) { + audioinfo.play.port &= oldinfo.play.mod_ports; + /* and add in any that are forced to be on */ + audioinfo.play.port |= (oldinfo.play.port & ~oldinfo.play.mod_ports); + } + } + g_return_if_fail (mixer->mixer_fd != -1); + + if (audioinfo.play.port != (guint) (-1) && + audioinfo.play.port != oldinfo.play.port) + GST_LOG_OBJECT (mixer, "Changing play port mask to 0x%08x", + audioinfo.play.port); + + if (ioctl (mixer->mixer_fd, AUDIO_SETINFO, &audioinfo) < 0) { + g_warning ("Error setting audio settings"); + return; + } +} + +void +gst_sunaudiomixer_ctrl_set_record (GstSunAudioMixerCtrl * mixer, + GstMixerTrack * track, gboolean record) +{ +} + +void +gst_sunaudiomixer_ctrl_set_option (GstSunAudioMixerCtrl * mixer, + GstMixerOptions * options, gchar * value) +{ + struct audio_info audioinfo; + GstMixerTrack *track; + GstSunAudioMixerOptions *opts; + GQuark q; + int i; + + g_return_if_fail (mixer != NULL); + g_return_if_fail (mixer->mixer_fd != -1); + g_return_if_fail (value != NULL); + g_return_if_fail (GST_IS_SUNAUDIO_MIXER_OPTIONS (options)); + + track = GST_MIXER_TRACK (options); + opts = GST_SUNAUDIO_MIXER_OPTIONS (options); + + if (opts->track_num != GST_SUNAUDIO_TRACK_RECSRC) { + g_warning ("set_option not supported on track %s", track->label); + return; + } + + q = g_quark_try_string (value); + if (q == 0) { + g_warning ("unknown option '%s'", value); + return; + } + + for (i = 0; i < 8; i++) { + if (opts->names[i] == q) { + break; + } + } + + if (((1 << (i)) & opts->avail) == 0) { + g_warning ("Record port %s not available", g_quark_to_string (q)); + return; + } + + AUDIO_INITINFO (&audioinfo); + audioinfo.record.port = (1 << (i)); + + if (ioctl (mixer->mixer_fd, AUDIO_SETINFO, &audioinfo) < 0) { + g_warning ("Error setting audio record port"); + } +} + +const gchar * +gst_sunaudiomixer_ctrl_get_option (GstSunAudioMixerCtrl * mixer, + GstMixerOptions * options) +{ + GstMixerTrack *track; + GstSunAudioMixerOptions *opts; + struct audio_info audioinfo; + int i; + + g_return_val_if_fail (mixer != NULL, NULL); + g_return_val_if_fail (mixer->fd != -1, NULL); + g_return_val_if_fail (GST_IS_SUNAUDIO_MIXER_OPTIONS (options), NULL); + + track = GST_MIXER_TRACK (options); + opts = GST_SUNAUDIO_MIXER_OPTIONS (options); + + g_return_val_if_fail (opts->track_num == GST_SUNAUDIO_TRACK_RECSRC, NULL); + + if (ioctl (mixer->mixer_fd, AUDIO_GETINFO, &audioinfo) < 0) { + g_warning ("Error getting audio device settings"); + return (NULL); + } + + for (i = 0; i < 8; i++) { + if ((1 << i) == audioinfo.record.port) { + const gchar *s = g_quark_to_string (opts->names[i]); + GST_DEBUG_OBJECT (mixer, "Getting value for option %d: %s", + opts->track_num, s); + return (s); + } + } + + GST_DEBUG_OBJECT (mixer, "Unable to get value for option %d", + opts->track_num); + + g_warning ("Record port value %d seems illegal", audioinfo.record.port); + return (NULL); +} diff --git a/sys/sunaudio/gstsunaudiomixerctrl.h b/sys/sunaudio/gstsunaudiomixerctrl.h new file mode 100644 index 0000000..d38f02f --- /dev/null +++ b/sys/sunaudio/gstsunaudiomixerctrl.h @@ -0,0 +1,189 @@ +/* + * GStreamer - SunAudio mixer interface element. + * Copyright (C) 2005,2006,2009 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.com> + * Copyright (C) 2009 Sun Microsystems, Inc., + * Garrett D'Amore <garrett.damore@sun.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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __GST_SUNAUDIO_MIXER_CTRL_H +#define __GST_SUNAUDIO_MIXER_CTRL_H + +#include <sys/audioio.h> + +#include <gst/gst.h> +#include <gst/interfaces/mixer.h> + +G_BEGIN_DECLS + +#define GST_SUNAUDIO_MIXER_CTRL(obj) ((GstSunAudioMixerCtrl*)(obj)) + +typedef struct _GstSunAudioMixerCtrl GstSunAudioMixerCtrl; + +struct _GstSunAudioMixerCtrl { + GList * tracklist; /* list of available tracks */ + + gint fd; + gint mixer_fd; + + gchar * device; +}; + +GstSunAudioMixerCtrl* gst_sunaudiomixer_ctrl_new (const gchar *device); +void gst_sunaudiomixer_ctrl_free (GstSunAudioMixerCtrl *mixer); + +const GList* gst_sunaudiomixer_ctrl_list_tracks (GstSunAudioMixerCtrl * mixer); +void gst_sunaudiomixer_ctrl_set_volume (GstSunAudioMixerCtrl * mixer, + GstMixerTrack * track, + gint * volumes); +void gst_sunaudiomixer_ctrl_get_volume (GstSunAudioMixerCtrl * mixer, + GstMixerTrack * track, + gint * volumes); +void gst_sunaudiomixer_ctrl_set_record (GstSunAudioMixerCtrl * mixer, + GstMixerTrack * track, + gboolean record); +void gst_sunaudiomixer_ctrl_set_mute (GstSunAudioMixerCtrl * mixer, + GstMixerTrack * track, + gboolean mute); +void gst_sunaudiomixer_ctrl_set_option (GstSunAudioMixerCtrl * mixer, + GstMixerOptions * options, + gchar * value); +const gchar * gst_sunaudiomixer_ctrl_get_option (GstSunAudioMixerCtrl * mixer, + GstMixerOptions * options); +GstMixerFlags gst_sunaudiomixer_ctrl_get_mixer_flags (GstSunAudioMixerCtrl *mixer); + +#define GST_IMPLEMENT_SUNAUDIO_MIXER_CTRL_METHODS(Type, interface_as_function) \ +static gboolean \ +interface_as_function ## _supported (Type *this, GType iface_type) \ +{ \ + g_assert (iface_type == GST_TYPE_MIXER); \ + \ + return (this->mixer != NULL); \ +} \ + \ +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_sunaudiomixer_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_sunaudiomixer_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_sunaudiomixer_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_sunaudiomixer_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_sunaudiomixer_ctrl_set_mute (this->mixer, track, mute); \ +} \ + \ +static const gchar * \ +interface_as_function ## _get_option (GstMixer * mixer, GstMixerOptions * opts) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_val_if_fail (this != NULL, NULL); \ + g_return_val_if_fail (this->mixer != NULL, NULL); \ + \ + return gst_sunaudiomixer_ctrl_get_option (this->mixer, opts); \ +} \ +\ +static void \ +interface_as_function ## _set_option (GstMixer * mixer, GstMixerOptions * opts, \ + gchar * value) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_if_fail (this != NULL); \ + g_return_if_fail (this->mixer != NULL); \ + \ + gst_sunaudiomixer_ctrl_set_option (this->mixer, opts, value); \ +} \ +\ +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_sunaudiomixer_ctrl_get_mixer_flags (this->mixer); \ +} \ + \ +static void \ +interface_as_function ## _interface_init (GstMixerClass * klass) \ +{ \ + GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; \ + \ + /* set up the interface hooks */ \ + 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_option = interface_as_function ## _get_option; \ + klass->set_option = interface_as_function ## _set_option; \ + klass->get_mixer_flags = interface_as_function ## _get_mixer_flags; \ +} + +G_END_DECLS + +#endif diff --git a/sys/sunaudio/gstsunaudiomixeroptions.c b/sys/sunaudio/gstsunaudiomixeroptions.c new file mode 100644 index 0000000..1fa025b --- /dev/null +++ b/sys/sunaudio/gstsunaudiomixeroptions.c @@ -0,0 +1,157 @@ +/* + * GStreamer SunAudio mixer track implementation + * Copyright (C) 2009 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.com> + * Garrett D'Amore <garrett.damore@sun.com> + * + * gstsunaudiomixeroptions.c: Sun Audio mixer options object + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/audio.h> +#include <sys/mixer.h> + +#include <gst/gst-i18n-plugin.h> + +#include "gstsunaudiomixeroptions.h" +#include "gstsunaudiomixertrack.h" + +GST_DEBUG_CATEGORY_EXTERN (sunaudio_debug); +#define GST_CAT_DEFAULT sunaudio_debug + +static void gst_sunaudiomixer_options_init (GstSunAudioMixerOptions * sun_opts); +static void gst_sunaudiomixer_options_class_init (gpointer g_class, + gpointer class_data); + +static GstMixerOptionsClass *parent_class = NULL; + +GType +gst_sunaudiomixer_options_get_type (void) +{ + static GType opts_type = 0; + + if (!opts_type) { + static const GTypeInfo opts_info = { + sizeof (GstSunAudioMixerOptionsClass), + NULL, + NULL, + gst_sunaudiomixer_options_class_init, + NULL, + NULL, + sizeof (GstSunAudioMixerOptions), + 0, + (GInstanceInitFunc) gst_sunaudiomixer_options_init, + }; + + opts_type = + g_type_register_static (GST_TYPE_MIXER_OPTIONS, + "GstSunAudioMixerOptions", &opts_info, 0); + } + + return opts_type; +} + +static void +gst_sunaudiomixer_options_class_init (gpointer g_class, gpointer class_data) +{ + parent_class = g_type_class_peek_parent (g_class); +} + +static void +gst_sunaudiomixer_options_init (GstSunAudioMixerOptions * sun_opts) +{ +} + +GstMixerOptions * +gst_sunaudiomixer_options_new (GstSunAudioMixerCtrl * mixer, gint track_num) +{ + GstMixerOptions *opts; + GstSunAudioMixerOptions *sun_opts; + GstMixerTrack *track; + const gchar *label; + gint i; + struct audio_info audioinfo; + + if ((mixer == NULL) || (mixer->mixer_fd == -1)) { + g_warning ("mixer not initialized"); + return NULL; + } + + if (track_num != GST_SUNAUDIO_TRACK_RECSRC) { + g_warning ("invalid options track"); + return (NULL); + } + + label = N_("Record Source"); + + opts = g_object_new (GST_TYPE_SUNAUDIO_MIXER_OPTIONS, + "untranslated-label", label, NULL); + sun_opts = GST_SUNAUDIO_MIXER_OPTIONS (opts); + track = GST_MIXER_TRACK (opts); + + GST_DEBUG_OBJECT (opts, "New mixer options, track %d: %s", + track_num, GST_STR_NULL (label)); + + /* save off names for the record sources */ + sun_opts->names[0] = g_quark_from_string (_("Microphone")); + sun_opts->names[1] = g_quark_from_string (_("Line In")); + sun_opts->names[2] = g_quark_from_string (_("Internal CD")); + sun_opts->names[3] = g_quark_from_string (_("SPDIF In")); + sun_opts->names[4] = g_quark_from_string (_("AUX 1 In")); + sun_opts->names[5] = g_quark_from_string (_("AUX 2 In")); + sun_opts->names[6] = g_quark_from_string (_("Codec Loopback")); + sun_opts->names[7] = g_quark_from_string (_("SunVTS Loopback")); + + /* set basic information */ + track->label = g_strdup (_(label)); + track->num_channels = 0; + track->min_volume = 0; + track->max_volume = 0; + track->flags = + GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_WHITELIST | + GST_MIXER_TRACK_NO_RECORD; + + if (ioctl (mixer->mixer_fd, AUDIO_GETINFO, &audioinfo) < 0) { + g_warning ("Error getting audio device settings"); + g_object_unref (G_OBJECT (sun_opts)); + return NULL; + } + + sun_opts->avail = audioinfo.record.avail_ports; + sun_opts->track_num = track_num; + + for (i = 0; i < 8; i++) { + if ((1 << i) & audioinfo.record.avail_ports) { + const char *s = g_quark_to_string (sun_opts->names[i]); + opts->values = g_list_append (opts->values, g_strdup (s)); + GST_DEBUG_OBJECT (opts, "option for track %d: %s", + track_num, GST_STR_NULL (s)); + } + } + + return opts; +} diff --git a/sys/sunaudio/gstsunaudiomixeroptions.h b/sys/sunaudio/gstsunaudiomixeroptions.h new file mode 100644 index 0000000..fb02b46 --- /dev/null +++ b/sys/sunaudio/gstsunaudiomixeroptions.h @@ -0,0 +1,65 @@ +/* + * GStreamer SunAudio mixer track implementation + * Copyright (C) 2009 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.com> + * Garrett D'Amore <garrett.damore@sun.com> + * + * gstsunaudiomixeroptions.h: Sun Audio mixer options object + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + */ + +#ifndef __GST_SUNAUDIO_MIXER_OPTIONS_H__ +#define __GST_SUNAUDIO_MIXER_OPTIONS_H__ + + +#include "gstsunaudiomixer.h" +#include <gst/interfaces/mixeroptions.h> + + +G_BEGIN_DECLS + + +#define GST_SUNAUDIO_MIXER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SUNAUDIO_MIXER_OPTIONS, GstSunAudioMixerOptions)) +#define GST_SUNAUDIO_MIXER_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SUNAUDIO_MIXER_OPTIONS, GstSunAudioMixerOptionsClass)) +#define GST_IS_SUNAUDIO_MIXER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SUNAUDIO_MIXER_OPTIONS)) +#define GST_IS_SUNAUDIO_MIXER_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SUNAUDIO_MIXER_OPTIONS)) +#define GST_TYPE_SUNAUDIO_MIXER_OPTIONS (gst_sunaudiomixer_options_get_type()) + + +typedef struct _GstSunAudioMixerOptions GstSunAudioMixerOptions; +typedef struct _GstSunAudioMixerOptionsClass GstSunAudioMixerOptionsClass; + + +struct _GstSunAudioMixerOptions { + GstMixerOptions parent; + gint track_num; + GQuark names[8]; /* only 8 possible */ + gint avail; /* mask of avail */ +}; + +struct _GstSunAudioMixerOptionsClass { + GstMixerOptionsClass parent; +}; + + +GType gst_sunaudiomixer_options_get_type (void); +GstMixerOptions *gst_sunaudiomixer_options_new (GstSunAudioMixerCtrl *mixer, gint track_num); + + +G_END_DECLS + + +#endif /* __GST_SUNAUDIO_MIXER_OPTIONS_H__ */ diff --git a/sys/sunaudio/gstsunaudiomixertrack.c b/sys/sunaudio/gstsunaudiomixertrack.c new file mode 100644 index 0000000..786ef0d --- /dev/null +++ b/sys/sunaudio/gstsunaudiomixertrack.c @@ -0,0 +1,158 @@ +/* + * GStreamer + * Copyright (C) 2005,2008, 2009 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.com> + * Copyright (C) 2009 Sun Microsystems, Inc., + * Garrett D'Amore <garrett.damore@sun.com> + * + * gstsunaudiomixer.c: mixer interface implementation for OSS + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/audioio.h> + +#include <gst/gst-i18n-plugin.h> + +#include "gstsunaudiomixertrack.h" + +GST_DEBUG_CATEGORY_EXTERN (sunaudio_debug); +#define GST_CAT_DEFAULT sunaudio_debug + +#define MASK_BIT_IS_SET(mask, bit) \ + (mask & (1 << bit)) + +G_DEFINE_TYPE (GstSunAudioMixerTrack, gst_sunaudiomixer_track, + GST_TYPE_MIXER_TRACK); + +static void +gst_sunaudiomixer_track_class_init (GstSunAudioMixerTrackClass * klass) +{ + /* nop */ +} + +static void +gst_sunaudiomixer_track_init (GstSunAudioMixerTrack * track) +{ + track->gain = 0; + track->balance = AUDIO_MID_BALANCE; + track->track_num = 0; +} + +GstMixerTrack * +gst_sunaudiomixer_track_new (GstSunAudioTrackType track_num) +{ + const gchar *labels[] = { N_("Volume"), + N_("Gain"), + N_("Monitor"), + N_("Built-in Speaker"), + N_("Headphone"), + N_("Line Out"), + N_("SPDIF Out"), + N_("AUX 1 Out"), + N_("AUX 2 Out"), + }; + + + GstSunAudioMixerTrack *sunaudiotrack; + GstMixerTrack *track; + const gchar *untranslated_label; + + if ((guint) track_num < G_N_ELEMENTS (labels)) + untranslated_label = labels[track_num]; + else + untranslated_label = NULL; + + sunaudiotrack = g_object_new (GST_TYPE_SUNAUDIO_MIXER_TRACK, + "untranslated-label", untranslated_label, NULL); + + GST_DEBUG_OBJECT (sunaudiotrack, "Creating new mixer track of type %d: %s", + track_num, GST_STR_NULL (untranslated_label)); + + switch (track_num) { + case GST_SUNAUDIO_TRACK_OUTPUT: + /* these are sliders */ + track = GST_MIXER_TRACK (sunaudiotrack); + track->label = g_strdup (_(untranslated_label)); + track->num_channels = 2; + track->flags = GST_MIXER_TRACK_OUTPUT | GST_MIXER_TRACK_WHITELIST | + GST_MIXER_TRACK_MASTER; + track->min_volume = 0; + track->max_volume = 255; + sunaudiotrack->track_num = track_num; + sunaudiotrack->gain = (0 & 0xff); + sunaudiotrack->balance = AUDIO_MID_BALANCE; + break; + case GST_SUNAUDIO_TRACK_RECORD: + /* these are sliders */ + track = GST_MIXER_TRACK (sunaudiotrack); + track->label = g_strdup (_(untranslated_label)); + track->num_channels = 2; + track->flags = GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD | + GST_MIXER_TRACK_WHITELIST; + track->min_volume = 0; + track->max_volume = 255; + sunaudiotrack->track_num = track_num; + sunaudiotrack->gain = (0 & 0xff); + sunaudiotrack->balance = AUDIO_MID_BALANCE; + break; + case GST_SUNAUDIO_TRACK_MONITOR: + /* these are sliders */ + track = GST_MIXER_TRACK (sunaudiotrack); + track->label = g_strdup (_(untranslated_label)); + track->num_channels = 2; + track->flags = GST_MIXER_TRACK_INPUT | GST_MIXER_TRACK_NO_RECORD; + track->min_volume = 0; + track->max_volume = 255; + sunaudiotrack->track_num = track_num; + sunaudiotrack->gain = (0 & 0xff); + sunaudiotrack->balance = AUDIO_MID_BALANCE; + break; + case GST_SUNAUDIO_TRACK_SPEAKER: + case GST_SUNAUDIO_TRACK_HP: + case GST_SUNAUDIO_TRACK_LINEOUT: + case GST_SUNAUDIO_TRACK_SPDIFOUT: + case GST_SUNAUDIO_TRACK_AUX1OUT: + case GST_SUNAUDIO_TRACK_AUX2OUT: + /* these are switches */ + track = GST_MIXER_TRACK (sunaudiotrack); + track->label = g_strdup (_(untranslated_label)); + track->num_channels = 0; + track->flags = GST_MIXER_TRACK_OUTPUT | GST_MIXER_TRACK_WHITELIST; + track->min_volume = 0; + track->max_volume = 255; + sunaudiotrack->track_num = track_num; + sunaudiotrack->gain = (0 & 0xff); + sunaudiotrack->balance = AUDIO_MID_BALANCE; + break; + default: + g_warning ("Unknown sun audio track num %d", track_num); + track = NULL; + } + + return track; +} diff --git a/sys/sunaudio/gstsunaudiomixertrack.h b/sys/sunaudio/gstsunaudiomixertrack.h new file mode 100644 index 0000000..83be9fc --- /dev/null +++ b/sys/sunaudio/gstsunaudiomixertrack.h @@ -0,0 +1,78 @@ +/* + * GStreamer SunAudio mixer track implementation + * Copyright (C) 2005,2006,2009 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.com> + * Copyright (C) 2009 Sun Microsystems, Inc., + * Garrett D'Amore <garrett.damore@sun.com> + * + * gstsunaudiomixertrack.h: SunAudio mixer tracks + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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_SUNAUDIO_MIXER_TRACK_H__ +#define __GST_SUNAUDIO_MIXER_TRACK_H__ + +#include <gst/gst.h> +#include <gst/interfaces/mixer.h> + +G_BEGIN_DECLS + +typedef enum +{ + GST_SUNAUDIO_TRACK_OUTPUT = 0, + GST_SUNAUDIO_TRACK_RECORD, + GST_SUNAUDIO_TRACK_MONITOR, + GST_SUNAUDIO_TRACK_SPEAKER, + GST_SUNAUDIO_TRACK_HP, + GST_SUNAUDIO_TRACK_LINEOUT, + GST_SUNAUDIO_TRACK_SPDIFOUT, + GST_SUNAUDIO_TRACK_AUX1OUT, + GST_SUNAUDIO_TRACK_AUX2OUT, + GST_SUNAUDIO_TRACK_RECSRC +} GstSunAudioTrackType; + +#define GST_TYPE_SUNAUDIO_MIXER_TRACK \ + (gst_sunaudiomixer_track_get_type ()) +#define GST_SUNAUDIO_MIXER_TRACK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SUNAUDIO_MIXER_TRACK, \ + GstSunAudioMixerTrack)) +#define GST_SUNAUDIO_MIXER_TRACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SUNAUDIO_MIXER_TRACK, \ + GstSunAudioMixerTrackClass)) +#define GST_IS_SUNAUDIO_MIXER_TRACK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SUNAUDIO_MIXER_TRACK)) +#define GST_IS_SUNAUDIO_MIXER_TRACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SUNAUDIO_MIXER_TRACK)) + +typedef struct _GstSunAudioMixerTrack { + GstMixerTrack parent; + + gint gain; + gint balance; + GstSunAudioTrackType track_num; +} GstSunAudioMixerTrack; + +typedef struct _GstSunAudioMixerTrackClass { + GstMixerTrackClass parent; +} GstSunAudioMixerTrackClass; + +GType gst_sunaudiomixer_track_get_type (void); +GstMixerTrack* gst_sunaudiomixer_track_new (GstSunAudioTrackType track_num); + +G_END_DECLS + +#endif /* __GST_SUNAUDIO_MIXER_TRACK_H__ */ diff --git a/sys/sunaudio/gstsunaudiosink.c b/sys/sunaudio/gstsunaudiosink.c new file mode 100644 index 0000000..2a3cf19 --- /dev/null +++ b/sys/sunaudio/gstsunaudiosink.c @@ -0,0 +1,651 @@ +/* + * GStreamer - SunAudio sink + * Copyright (C) 2004 David A. Schleef <ds@schleef.org> + * Copyright (C) 2005,2006 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.com> + * Copyright (C) 2006 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. + */ + +/** + * SECTION:element-sunaudiosink + * + * sunaudiosink is an audio sink designed to work with the Sun Audio + * interface available in Solaris. + * + * <refsect2> + * <title>Example launch line</title> + * |[ + * gst-launch audiotestsrc volume=0.5 ! sunaudiosink + * ]| + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <fcntl.h> +#include <string.h> +#include <stropts.h> +#include <unistd.h> +#include <sys/mman.h> + +#include "gstsunaudiosink.h" + +GST_DEBUG_CATEGORY_EXTERN (sunaudio_debug); +#define GST_CAT_DEFAULT sunaudio_debug + +static void gst_sunaudiosink_base_init (gpointer g_class); +static void gst_sunaudiosink_class_init (GstSunAudioSinkClass * klass); +static void gst_sunaudiosink_init (GstSunAudioSink * filter); +static void gst_sunaudiosink_dispose (GObject * object); +static void gst_sunaudiosink_finalize (GObject * object); + +static void gst_sunaudiosink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_sunaudiosink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstCaps *gst_sunaudiosink_getcaps (GstBaseSink * bsink); + +static gboolean gst_sunaudiosink_open (GstAudioSink * asink); +static gboolean gst_sunaudiosink_close (GstAudioSink * asink); +static gboolean gst_sunaudiosink_prepare (GstAudioSink * asink, + GstRingBufferSpec * spec); +static gboolean gst_sunaudiosink_unprepare (GstAudioSink * asink); +static guint gst_sunaudiosink_write (GstAudioSink * asink, gpointer data, + guint length); +static guint gst_sunaudiosink_delay (GstAudioSink * asink); +static void gst_sunaudiosink_reset (GstAudioSink * asink); + +#define DEFAULT_DEVICE "/dev/audio" +enum +{ + PROP_0, + PROP_DEVICE, +}; + +static GstStaticPadTemplate gst_sunaudiosink_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, " + /* [5510,48000] seems to be a Solaris limit */ + "rate = (int) [ 5510, 48000 ], " "channels = (int) [ 1, 2 ]") + ); + +static GstElementClass *parent_class = NULL; + +GType +gst_sunaudiosink_get_type (void) +{ + static GType plugin_type = 0; + + if (!plugin_type) { + static const GTypeInfo plugin_info = { + sizeof (GstSunAudioSinkClass), + gst_sunaudiosink_base_init, + NULL, + (GClassInitFunc) gst_sunaudiosink_class_init, + NULL, + NULL, + sizeof (GstSunAudioSink), + 0, + (GInstanceInitFunc) gst_sunaudiosink_init, + }; + + plugin_type = g_type_register_static (GST_TYPE_AUDIO_SINK, + "GstSunAudioSink", &plugin_info, 0); + } + return plugin_type; +} + +static void +gst_sunaudiosink_dispose (GObject * object) +{ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_sunaudiosink_finalize (GObject * object) +{ + GstSunAudioSink *sunaudiosink = GST_SUNAUDIO_SINK (object); + + g_mutex_free (sunaudiosink->write_mutex); + g_cond_free (sunaudiosink->sleep_cond); + + g_free (sunaudiosink->device); + + if (sunaudiosink->fd != -1) { + close (sunaudiosink->fd); + sunaudiosink->fd = -1; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_sunaudiosink_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_static_pad_template (element_class, + &gst_sunaudiosink_factory); + gst_element_class_set_details_simple (element_class, "Sun Audio Sink", + "Sink/Audio", + "Audio sink for Sun Audio devices", + "David A. Schleef <ds@schleef.org>, " + "Brian Cameron <brian.cameron@sun.com>"); +} + +static void +gst_sunaudiosink_class_init (GstSunAudioSinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *gstbasesink_class; + GstBaseAudioSinkClass *gstbaseaudiosink_class; + GstAudioSinkClass *gstaudiosink_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesink_class = (GstBaseSinkClass *) klass; + gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass; + gstaudiosink_class = (GstAudioSinkClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->dispose = gst_sunaudiosink_dispose; + gobject_class->finalize = gst_sunaudiosink_finalize; + + gobject_class->set_property = gst_sunaudiosink_set_property; + gobject_class->get_property = gst_sunaudiosink_get_property; + + gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_sunaudiosink_getcaps); + + gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_sunaudiosink_open); + gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_sunaudiosink_close); + gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_sunaudiosink_prepare); + gstaudiosink_class->unprepare = + GST_DEBUG_FUNCPTR (gst_sunaudiosink_unprepare); + gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_sunaudiosink_write); + gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_sunaudiosink_delay); + gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_sunaudiosink_reset); + + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", "Audio Device (/dev/audio)", + DEFAULT_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +static void +gst_sunaudiosink_init (GstSunAudioSink * sunaudiosink) +{ + const char *audiodev; + + GST_DEBUG_OBJECT (sunaudiosink, "initializing sunaudiosink"); + + sunaudiosink->fd = -1; + + audiodev = g_getenv ("AUDIODEV"); + if (audiodev == NULL) + audiodev = DEFAULT_DEVICE; + sunaudiosink->device = g_strdup (audiodev); + + /* mutex and gcond used to control the write method */ + sunaudiosink->write_mutex = g_mutex_new (); + sunaudiosink->sleep_cond = g_cond_new (); +} + +static void +gst_sunaudiosink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstSunAudioSink *sunaudiosink; + + sunaudiosink = GST_SUNAUDIO_SINK (object); + + switch (prop_id) { + case PROP_DEVICE: + GST_OBJECT_LOCK (sunaudiosink); + g_free (sunaudiosink->device); + sunaudiosink->device = g_strdup (g_value_get_string (value)); + GST_OBJECT_UNLOCK (sunaudiosink); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_sunaudiosink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstSunAudioSink *sunaudiosink; + + sunaudiosink = GST_SUNAUDIO_SINK (object); + + switch (prop_id) { + case PROP_DEVICE: + GST_OBJECT_LOCK (sunaudiosink); + g_value_set_string (value, sunaudiosink->device); + GST_OBJECT_UNLOCK (sunaudiosink); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstCaps * +gst_sunaudiosink_getcaps (GstBaseSink * bsink) +{ + GstPadTemplate *pad_template; + GstCaps *caps = NULL; + GstSunAudioSink *sunaudiosink = GST_SUNAUDIO_SINK (bsink); + + GST_DEBUG_OBJECT (sunaudiosink, "getcaps called"); + + pad_template = gst_static_pad_template_get (&gst_sunaudiosink_factory); + caps = gst_caps_copy (gst_pad_template_get_caps (pad_template)); + + gst_object_unref (pad_template); + + return caps; +} + +static gboolean +gst_sunaudiosink_open (GstAudioSink * asink) +{ + GstSunAudioSink *sunaudiosink = GST_SUNAUDIO_SINK (asink); + int fd, ret; + + /* First try to open non-blocking */ + GST_OBJECT_LOCK (sunaudiosink); + fd = open (sunaudiosink->device, O_WRONLY | O_NONBLOCK); + + if (fd >= 0) { + close (fd); + fd = open (sunaudiosink->device, O_WRONLY); + } + + if (fd == -1) { + GST_OBJECT_UNLOCK (sunaudiosink); + goto open_failed; + } + + sunaudiosink->fd = fd; + GST_OBJECT_UNLOCK (sunaudiosink); + + ret = ioctl (fd, AUDIO_GETDEV, &sunaudiosink->dev); + if (ret == -1) + goto ioctl_error; + + GST_DEBUG_OBJECT (sunaudiosink, "name %s", sunaudiosink->dev.name); + GST_DEBUG_OBJECT (sunaudiosink, "version %s", sunaudiosink->dev.version); + GST_DEBUG_OBJECT (sunaudiosink, "config %s", sunaudiosink->dev.config); + + ret = ioctl (fd, AUDIO_GETINFO, &sunaudiosink->info); + if (ret == -1) + goto ioctl_error; + + GST_DEBUG_OBJECT (sunaudiosink, "monitor_gain %d", + sunaudiosink->info.monitor_gain); + GST_DEBUG_OBJECT (sunaudiosink, "output_muted %d", + sunaudiosink->info.output_muted); + GST_DEBUG_OBJECT (sunaudiosink, "hw_features %08x", + sunaudiosink->info.hw_features); + GST_DEBUG_OBJECT (sunaudiosink, "sw_features %08x", + sunaudiosink->info.sw_features); + GST_DEBUG_OBJECT (sunaudiosink, "sw_features_enabled %08x", + sunaudiosink->info.sw_features_enabled); + + return TRUE; + +open_failed: + GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, OPEN_WRITE, (NULL), + ("can't open connection to Sun Audio device %s", sunaudiosink->device)); + return FALSE; +ioctl_error: + close (sunaudiosink->fd); + GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + return FALSE; +} + +static gboolean +gst_sunaudiosink_close (GstAudioSink * asink) +{ + GstSunAudioSink *sunaudiosink = GST_SUNAUDIO_SINK (asink); + + if (sunaudiosink->fd != -1) { + close (sunaudiosink->fd); + sunaudiosink->fd = -1; + } + return TRUE; +} + +static gboolean +gst_sunaudiosink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) +{ + GstSunAudioSink *sunaudiosink = GST_SUNAUDIO_SINK (asink); + audio_info_t ainfo; + int ret; + int ports; + + ret = ioctl (sunaudiosink->fd, AUDIO_GETINFO, &ainfo); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + return FALSE; + } + + if (spec->width != 16) + return FALSE; + + ports = ainfo.play.port; + + AUDIO_INITINFO (&ainfo); + + ainfo.play.sample_rate = spec->rate; + ainfo.play.channels = spec->channels; + ainfo.play.precision = spec->width; + ainfo.play.encoding = AUDIO_ENCODING_LINEAR; + ainfo.play.port = ports; + + /* buffer_time for playback is not implemented in Solaris at the moment, + but at some point in the future, it might be */ + ainfo.play.buffer_size = + gst_util_uint64_scale (spec->rate * spec->bytes_per_sample, + spec->buffer_time, GST_SECOND / GST_USECOND); + + spec->silence_sample[0] = 0; + spec->silence_sample[1] = 0; + spec->silence_sample[2] = 0; + spec->silence_sample[3] = 0; + + ret = ioctl (sunaudiosink->fd, AUDIO_SETINFO, &ainfo); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + return FALSE; + } + + /* Now read back the info to find out the actual buffer size and set + segtotal */ + AUDIO_INITINFO (&ainfo); + + ret = ioctl (sunaudiosink->fd, AUDIO_GETINFO, &ainfo); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + return FALSE; + } +#if 0 + /* We don't actually use the buffer_size from the sound device, because + * it seems it's just bogus sometimes */ + sunaudiosink->segtotal = spec->segtotal = + ainfo.play.buffer_size / spec->segsize; +#else + sunaudiosink->segtotal = spec->segtotal; +#endif + sunaudiosink->segtotal_samples = + spec->segtotal * spec->segsize / spec->bytes_per_sample; + + sunaudiosink->segs_written = (gint) ainfo.play.eof; + sunaudiosink->samples_written = ainfo.play.samples; + sunaudiosink->bytes_per_sample = spec->bytes_per_sample; + + GST_DEBUG_OBJECT (sunaudiosink, "Got device buffer_size of %u", + ainfo.play.buffer_size); + + return TRUE; +} + +static gboolean +gst_sunaudiosink_unprepare (GstAudioSink * asink) +{ + return TRUE; +} + +#define LOOP_WHILE_EINTR(v,func) do { (v) = (func); } \ + while ((v) == -1 && errno == EINTR); + +/* Called with the write_mutex held */ +static void +gst_sunaudio_sink_do_delay (GstSunAudioSink * sink) +{ + GstBaseAudioSink *ba_sink = GST_BASE_AUDIO_SINK (sink); + GstClockTime total_sleep; + GstClockTime max_sleep; + gint sleep_usecs; + GTimeVal sleep_end; + gint err; + audio_info_t ainfo; + guint diff; + + /* This code below ensures that we don't race any further than buffer_time + * ahead of the audio output, by sleeping if the next write call would cause + * us to advance too far in the ring-buffer */ + LOOP_WHILE_EINTR (err, ioctl (sink->fd, AUDIO_GETINFO, &ainfo)); + if (err < 0) + goto write_error; + + /* Compute our offset from the output (copes with overflow) */ + diff = (guint) (sink->segs_written) - ainfo.play.eof; + if (diff > sink->segtotal) { + /* This implies that reset did a flush just as the sound device aquired + * some buffers internally, and it causes us to be out of sync with the + * eof measure. This corrects it */ + sink->segs_written = ainfo.play.eof; + diff = 0; + } + + if (diff + 1 < sink->segtotal) + return; /* no need to sleep at all */ + + /* Never sleep longer than the initial number of undrained segments in the + device plus one */ + total_sleep = 0; + max_sleep = (diff + 1) * (ba_sink->latency_time * GST_USECOND); + /* sleep for a segment period between .eof polls */ + sleep_usecs = ba_sink->latency_time; + + /* Current time is our reference point */ + g_get_current_time (&sleep_end); + + /* If the next segment would take us too far along the ring buffer, + * sleep for a bit to free up a slot. If there were a way to find out + * when the eof field actually increments, we could use, but the only + * notification mechanism seems to be SIGPOLL, which we can't use from + * a support library */ + while (diff + 1 >= sink->segtotal && total_sleep < max_sleep) { + GST_LOG_OBJECT (sink, "need to block to drain segment(s). " + "Sleeping for %d us", sleep_usecs); + + g_time_val_add (&sleep_end, sleep_usecs); + + if (g_cond_timed_wait (sink->sleep_cond, sink->write_mutex, &sleep_end)) { + GST_LOG_OBJECT (sink, "Waking up early due to reset"); + return; /* Got told to wake up */ + } + total_sleep += (sleep_usecs * GST_USECOND); + + LOOP_WHILE_EINTR (err, ioctl (sink->fd, AUDIO_GETINFO, &ainfo)); + if (err < 0) + goto write_error; + + /* Compute our (new) offset from the output (copes with overflow) */ + diff = (guint) g_atomic_int_get (&sink->segs_written) - ainfo.play.eof; + } + + return; + +write_error: + GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL), + ("Playback error on device '%s': %s", sink->device, strerror (errno))); + return; +} + +static guint +gst_sunaudiosink_write (GstAudioSink * asink, gpointer data, guint length) +{ + GstSunAudioSink *sink = GST_SUNAUDIO_SINK (asink); + + gint bytes_written, err; + + g_mutex_lock (sink->write_mutex); + if (sink->flushing) { + /* Exit immediately if reset tells us to */ + g_mutex_unlock (sink->write_mutex); + return length; + } + + LOOP_WHILE_EINTR (bytes_written, write (sink->fd, data, length)); + if (bytes_written < 0) { + err = bytes_written; + goto write_error; + } + + /* Increment our sample counter, for delay calcs */ + g_atomic_int_add (&sink->samples_written, length / sink->bytes_per_sample); + + /* Don't consider the segment written if we didn't output the whole lot yet */ + if (bytes_written < length) { + g_mutex_unlock (sink->write_mutex); + return (guint) bytes_written; + } + + /* Write a zero length output to trigger increment of the eof field */ + LOOP_WHILE_EINTR (err, write (sink->fd, NULL, 0)); + if (err < 0) + goto write_error; + + /* Count this extra segment we've written */ + sink->segs_written += 1; + + /* Now delay so we don't overrun the ring buffer */ + gst_sunaudio_sink_do_delay (sink); + + g_mutex_unlock (sink->write_mutex); + return length; + +write_error: + g_mutex_unlock (sink->write_mutex); + + GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL), + ("Playback error on device '%s': %s", sink->device, strerror (errno))); + return length; /* Say we wrote the segment to let the ringbuffer exit */ +} + +/* + * Provide the current number of unplayed samples that have been written + * to the device */ +static guint +gst_sunaudiosink_delay (GstAudioSink * asink) +{ + GstSunAudioSink *sink = GST_SUNAUDIO_SINK (asink); + audio_info_t ainfo; + gint ret; + guint offset; + + ret = ioctl (sink->fd, AUDIO_GETINFO, &ainfo); + if (G_UNLIKELY (ret == -1)) + return 0; + + offset = (g_atomic_int_get (&sink->samples_written) - ainfo.play.samples); + + /* If the offset is larger than the total ringbuffer size, then we asked + between the write call and when samples_written is updated */ + if (G_UNLIKELY (offset > sink->segtotal_samples)) + return 0; + + return offset; +} + +static void +gst_sunaudiosink_reset (GstAudioSink * asink) +{ + /* Get current values */ + GstSunAudioSink *sunaudiosink = GST_SUNAUDIO_SINK (asink); + audio_info_t ainfo; + int ret; + + ret = ioctl (sunaudiosink->fd, AUDIO_GETINFO, &ainfo); + if (ret == -1) { + /* + * Should never happen, but if we couldn't getinfo, then no point + * trying to setinfo + */ + GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + return; + } + + /* + * Pause the audio - so audio stops playing immediately rather than + * waiting for the ringbuffer to empty. + */ + ainfo.play.pause = !NULL; + ret = ioctl (sunaudiosink->fd, AUDIO_SETINFO, &ainfo); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + } + + /* Flush the audio */ + ret = ioctl (sunaudiosink->fd, I_FLUSH, FLUSHW); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + } + + /* Now, we take the write_mutex and signal to ensure the write thread + * is not busy, and we signal the condition to wake up any sleeper, + * then we flush again in case the write wrote something after we flushed, + * and finally release the lock and unpause */ + g_mutex_lock (sunaudiosink->write_mutex); + sunaudiosink->flushing = TRUE; + + g_cond_signal (sunaudiosink->sleep_cond); + + ret = ioctl (sunaudiosink->fd, I_FLUSH, FLUSHW); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + } + + /* unpause the audio */ + ainfo.play.pause = NULL; + ret = ioctl (sunaudiosink->fd, AUDIO_SETINFO, &ainfo); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosink, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + } + + /* After flushing the audio device, we need to remeasure the sample count + * and segments written count so we're in sync with the device */ + + sunaudiosink->segs_written = ainfo.play.eof; + g_atomic_int_set (&sunaudiosink->samples_written, ainfo.play.samples); + + sunaudiosink->flushing = FALSE; + g_mutex_unlock (sunaudiosink->write_mutex); +} diff --git a/sys/sunaudio/gstsunaudiosink.h b/sys/sunaudio/gstsunaudiosink.h new file mode 100644 index 0000000..9454475 --- /dev/null +++ b/sys/sunaudio/gstsunaudiosink.h @@ -0,0 +1,78 @@ +/* + * GStreamer - SunAudio sink + * Copyright (C) 2004 David A. Schleef <ds@schleef.org> + * Copyright (C) 2005,2006 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.com> + * Copyright (C) 2006 Jan Schmidt <thaytan@mad.scientist.com> + * + * gstsunaudiosink.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_SUNAUDIO_SINK_H__ +#define __GST_SUNAUDIO_SINK_H__ + +#include <sys/audioio.h> +#include <gst/gst.h> +#include <gst/audio/gstaudiosink.h> + +G_BEGIN_DECLS + +#define GST_TYPE_SUNAUDIO_SINK (gst_sunaudiosink_get_type()) +#define GST_SUNAUDIO_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SUNAUDIO_SINK,GstSunAudioSink)) +#define GST_SUNAUDIO_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SUNAUDIO_SINK,GstSunAudioSinkClass)) +#define GST_IS_SUNAUDIO_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SUNAUDIO_SINK)) +#define GST_IS_SUNAUDIO_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SUNAUDIO_SINK)) + +typedef struct _GstSunAudioSink GstSunAudioSink; +typedef struct _GstSunAudioSinkClass GstSunAudioSinkClass; + +struct _GstSunAudioSink { + GstAudioSink sink; + + gchar *device; + gint fd; + + audio_device_t dev; + audio_info_t info; + + /* Number of segments the ringbuffer is configured for */ + guint segtotal; + guint segtotal_samples; + + /* Number of segments written to the device */ + gint segs_written; + /* Number of samples written to the device */ + gint samples_written; + guint bytes_per_sample; + + /* mutex and gcond used to control the write method */ + GMutex *write_mutex; + GCond *sleep_cond; + gboolean flushing; +}; + +struct _GstSunAudioSinkClass { + GstAudioSinkClass parent_class; +}; + +GType gst_sunaudiosink_get_type(void); + +G_END_DECLS + +#endif /* __GST_SUNAUDIO_SINK_H__ */ + diff --git a/sys/sunaudio/gstsunaudiosrc.c b/sys/sunaudio/gstsunaudiosrc.c new file mode 100644 index 0000000..08282cf --- /dev/null +++ b/sys/sunaudio/gstsunaudiosrc.c @@ -0,0 +1,423 @@ +/* + * GStreamer - SunAudio source + * Copyright (C) 2005,2006 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.com> + * + * gstsunaudiosrc.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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-sunaudiosrc + * + * sunaudiosrc is an audio source designed to work with the Sun Audio + * interface available in Solaris. + * + * <refsect2> + * <title>Example launch line</title> + * |[ + * gst-launch sunaudiosrc ! wavenc ! filesink location=audio.wav + * ]| + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <stropts.h> +#include <sys/mixer.h> + +#include "gstsunaudiosrc.h" + +GST_DEBUG_CATEGORY_EXTERN (sunaudio_debug); +#define GST_CAT_DEFAULT sunaudio_debug + +static void gst_sunaudiosrc_base_init (gpointer g_class); +static void gst_sunaudiosrc_class_init (GstSunAudioSrcClass * klass); +static void gst_sunaudiosrc_init (GstSunAudioSrc * sunaudiosrc, + GstSunAudioSrcClass * g_class); +static void gst_sunaudiosrc_dispose (GObject * object); + +static void gst_sunaudiosrc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_sunaudiosrc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstCaps *gst_sunaudiosrc_getcaps (GstBaseSrc * bsrc); + +static gboolean gst_sunaudiosrc_open (GstAudioSrc * asrc); +static gboolean gst_sunaudiosrc_close (GstAudioSrc * asrc); +static gboolean gst_sunaudiosrc_prepare (GstAudioSrc * asrc, + GstRingBufferSpec * spec); +static gboolean gst_sunaudiosrc_unprepare (GstAudioSrc * asrc); +static guint gst_sunaudiosrc_read (GstAudioSrc * asrc, gpointer data, + guint length); +static guint gst_sunaudiosrc_delay (GstAudioSrc * asrc); +static void gst_sunaudiosrc_reset (GstAudioSrc * asrc); + +#define DEFAULT_DEVICE "/dev/audio" + +enum +{ + PROP_0, + PROP_DEVICE +}; + +GST_BOILERPLATE_WITH_INTERFACE (GstSunAudioSrc, gst_sunaudiosrc, + GstAudioSrc, GST_TYPE_AUDIO_SRC, GstMixer, GST_TYPE_MIXER, gst_sunaudiosrc); + +GST_IMPLEMENT_SUNAUDIO_MIXER_CTRL_METHODS (GstSunAudioSrc, gst_sunaudiosrc); + +static GstStaticPadTemplate gst_sunaudiosrc_factory = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "endianness = (int) BYTE_ORDER, " + "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16, " + /* [5510,48000] seems to be a Solaris limit */ + "rate = (int) [ 5510, 48000 ], " "channels = (int) [ 1, 2 ]") + ); + +static void +gst_sunaudiosrc_dispose (GObject * object) +{ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_sunaudiosrc_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_static_pad_template (element_class, + &gst_sunaudiosrc_factory); + gst_element_class_set_details_simple (element_class, "Sun Audio Source", + "Source/Audio", + "Audio source for Sun Audio devices", + "Brian Cameron <brian.cameron@sun.com>"); +} + +static void +gst_sunaudiosrc_class_init (GstSunAudioSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSrcClass *gstbasesrc_class; + GstBaseAudioSrcClass *gstbaseaudiosrc_class; + GstAudioSrcClass *gstaudiosrc_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesrc_class = (GstBaseSrcClass *) klass; + gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass; + gstaudiosrc_class = (GstAudioSrcClass *) klass; + + gobject_class->dispose = gst_sunaudiosrc_dispose; + gobject_class->get_property = gst_sunaudiosrc_get_property; + gobject_class->set_property = gst_sunaudiosrc_set_property; + + gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_getcaps); + + gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_open); + gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_prepare); + gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_unprepare); + gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_close); + gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_read); + gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_delay); + gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_reset); + + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", + "SunAudio device (usually /dev/audio)", DEFAULT_DEVICE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +static void +gst_sunaudiosrc_init (GstSunAudioSrc * sunaudiosrc, + GstSunAudioSrcClass * g_class) +{ + const char *audiodev; + + GST_DEBUG_OBJECT (sunaudiosrc, "initializing sunaudiosrc"); + + sunaudiosrc->fd = -1; + + audiodev = g_getenv ("AUDIODEV"); + if (audiodev == NULL) + audiodev = DEFAULT_DEVICE; + sunaudiosrc->device = g_strdup (audiodev); +} + +static void +gst_sunaudiosrc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstSunAudioSrc *sunaudiosrc; + + sunaudiosrc = GST_SUNAUDIO_SRC (object); + + switch (prop_id) { + case PROP_DEVICE: + if (sunaudiosrc->device) + g_free (sunaudiosrc->device); + sunaudiosrc->device = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_sunaudiosrc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstSunAudioSrc *sunaudiosrc; + + sunaudiosrc = GST_SUNAUDIO_SRC (object); + + switch (prop_id) { + case PROP_DEVICE: + g_value_set_string (value, sunaudiosrc->device); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstCaps * +gst_sunaudiosrc_getcaps (GstBaseSrc * bsrc) +{ + GstPadTemplate *pad_template; + GstCaps *caps = NULL; + GstSunAudioSrc *sunaudiosrc = GST_SUNAUDIO_SRC (bsrc); + + GST_DEBUG_OBJECT (sunaudiosrc, "getcaps called"); + + pad_template = gst_static_pad_template_get (&gst_sunaudiosrc_factory); + caps = gst_caps_copy (gst_pad_template_get_caps (pad_template)); + + gst_object_unref (pad_template); + + return caps; +} + +static gboolean +gst_sunaudiosrc_open (GstAudioSrc * asrc) +{ + GstSunAudioSrc *sunaudiosrc = GST_SUNAUDIO_SRC (asrc); + int fd, ret; + + fd = open (sunaudiosrc->device, O_RDONLY); + + if (fd == -1) { + GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, OPEN_READ, (NULL), + ("can't open connection to Sun Audio device %s", sunaudiosrc->device)); + + return FALSE; + } + + sunaudiosrc->fd = fd; + + ret = ioctl (fd, AUDIO_GETDEV, &sunaudiosrc->dev); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + return FALSE; + } + + GST_DEBUG_OBJECT (sunaudiosrc, "name %s", sunaudiosrc->dev.name); + GST_DEBUG_OBJECT (sunaudiosrc, "version %s", sunaudiosrc->dev.version); + GST_DEBUG_OBJECT (sunaudiosrc, "config %s", sunaudiosrc->dev.config); + + ret = ioctl (fd, AUDIO_GETINFO, &sunaudiosrc->info); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + return FALSE; + } + + GST_DEBUG_OBJECT (sunaudiosrc, "monitor_gain %d", + sunaudiosrc->info.monitor_gain); + GST_DEBUG_OBJECT (sunaudiosrc, "output_muted %d", + sunaudiosrc->info.output_muted); + GST_DEBUG_OBJECT (sunaudiosrc, "hw_features %08x", + sunaudiosrc->info.hw_features); + GST_DEBUG_OBJECT (sunaudiosrc, "sw_features %08x", + sunaudiosrc->info.sw_features); + GST_DEBUG_OBJECT (sunaudiosrc, "sw_features_enabled %08x", + sunaudiosrc->info.sw_features_enabled); + + if (!sunaudiosrc->mixer) { + const char *audiodev; + + audiodev = g_getenv ("AUDIODEV"); + if (audiodev == NULL) { + sunaudiosrc->mixer = gst_sunaudiomixer_ctrl_new ("/dev/audioctl"); + } else { + gchar *device = g_strdup_printf ("%sctl", audiodev); + + sunaudiosrc->mixer = gst_sunaudiomixer_ctrl_new (device); + g_free (device); + } + } + + return TRUE; +} + +static gboolean +gst_sunaudiosrc_close (GstAudioSrc * asrc) +{ + GstSunAudioSrc *sunaudiosrc = GST_SUNAUDIO_SRC (asrc); + + close (sunaudiosrc->fd); + sunaudiosrc->fd = -1; + + if (sunaudiosrc->mixer) { + gst_sunaudiomixer_ctrl_free (sunaudiosrc->mixer); + sunaudiosrc->mixer = NULL; + } + + return TRUE; +} + +static gboolean +gst_sunaudiosrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec) +{ + GstSunAudioSrc *sunaudiosrc = GST_SUNAUDIO_SRC (asrc); + audio_info_t ainfo; + int ret; + GstSunAudioMixerCtrl *mixer; + struct audio_info audioinfo; + + ret = ioctl (sunaudiosrc->fd, AUDIO_GETINFO, &ainfo); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + return FALSE; + } + + if (spec->width != 16) + return FALSE; + + AUDIO_INITINFO (&ainfo); + + ainfo.record.sample_rate = spec->rate; + ainfo.record.precision = spec->width; + ainfo.record.channels = spec->channels; + ainfo.record.encoding = AUDIO_ENCODING_LINEAR; + ainfo.record.buffer_size = spec->buffer_time; + + mixer = sunaudiosrc->mixer; + + if (ioctl (mixer->mixer_fd, AUDIO_GETINFO, &audioinfo) < 0) { + g_warning ("Error getting audio device volume"); + } + ainfo.record.port = audioinfo.record.port; + ainfo.record.gain = audioinfo.record.gain; + ainfo.record.balance = audioinfo.record.balance; + + spec->segsize = 128; + spec->segtotal = spec->buffer_time / 128; + + spec->silence_sample[0] = 0; + spec->silence_sample[1] = 0; + spec->silence_sample[2] = 0; + spec->silence_sample[3] = 0; + + ret = ioctl (sunaudiosrc->fd, AUDIO_SETINFO, &ainfo); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + return FALSE; + } + + + ioctl (sunaudiosrc->fd, I_FLUSH, FLUSHR); + + return TRUE; +} + +static gboolean +gst_sunaudiosrc_unprepare (GstAudioSrc * asrc) +{ + return TRUE; +} + +static guint +gst_sunaudiosrc_read (GstAudioSrc * asrc, gpointer data, guint length) +{ + return read (GST_SUNAUDIO_SRC (asrc)->fd, data, length); +} + +static guint +gst_sunaudiosrc_delay (GstAudioSrc * asrc) +{ + return 0; +} + +static void +gst_sunaudiosrc_reset (GstAudioSrc * asrc) +{ + /* Get current values */ + GstSunAudioSrc *sunaudiosrc = GST_SUNAUDIO_SRC (asrc); + audio_info_t ainfo; + int ret; + + ret = ioctl (sunaudiosrc->fd, AUDIO_GETINFO, &ainfo); + if (ret == -1) { + /* + * Should never happen, but if we couldn't getinfo, then no point + * trying to setinfo + */ + GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + return; + } + + /* + * Pause the audio - so audio stops playing immediately rather than + * waiting for the ringbuffer to empty. + */ + ainfo.record.pause = !NULL; + ret = ioctl (sunaudiosrc->fd, AUDIO_SETINFO, &ainfo); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + } + + /* Flush the audio */ + ret = ioctl (sunaudiosrc->fd, I_FLUSH, FLUSHR); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + } + + /* unpause the audio */ + ainfo.record.pause = NULL; + ret = ioctl (sunaudiosrc->fd, AUDIO_SETINFO, &ainfo); + if (ret == -1) { + GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s", + strerror (errno))); + } +} diff --git a/sys/sunaudio/gstsunaudiosrc.h b/sys/sunaudio/gstsunaudiosrc.h new file mode 100644 index 0000000..95d9613 --- /dev/null +++ b/sys/sunaudio/gstsunaudiosrc.h @@ -0,0 +1,67 @@ +/* GStreamer - SunAudio source + * Copyright (C) 2005,2006 Sun Microsystems, Inc., + * Brian Cameron <brian.cameron@sun.com> + * + * gstsunaudiosrc.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_SUNAUDIO_SRC_H__ +#define __GST_SUNAUDIO_SRC_H__ + +#include <sys/audioio.h> +#include <gst/gst.h> +#include <gst/audio/gstaudiosrc.h> + +#include "gstsunaudiomixerctrl.h" + +G_BEGIN_DECLS + +#define GST_TYPE_SUNAUDIO_SRC (gst_sunaudiosrc_get_type()) +#define GST_SUNAUDIO_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SUNAUDIO_SRC,GstSunAudioSrc)) +#define GST_SUNAUDIO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SUNAUDIO_SRC,GstSunAudioSrcClass)) +#define GST_IS_SUNAUDIO_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SUNAUDIO_SRC)) +#define GST_IS_SUNAUDIO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SUNAUDIO_SRC)) + +typedef struct _GstSunAudioSrc GstSunAudioSrc; +typedef struct _GstSunAudioSrcClass GstSunAudioSrcClass; + +struct _GstSunAudioSrc { + GstAudioSrc src; + + gchar *device; + gint fd; + gint control_fd; + + audio_device_t dev; + audio_info_t info; + + gint bytes_per_sample; + + GstSunAudioMixerCtrl *mixer; +}; + +struct _GstSunAudioSrcClass { + GstAudioSrcClass parent_class; +}; + +GType gst_sunaudiosrc_get_type(void); + +G_END_DECLS + +#endif /* __GST_SUNAUDIO_SRC_H__ */ + diff --git a/sys/v4l2/Makefile.am b/sys/v4l2/Makefile.am new file mode 100644 index 0000000..a7a99de --- /dev/null +++ b/sys/v4l2/Makefile.am @@ -0,0 +1,60 @@ +plugin_LTLIBRARIES = libgstvideo4linux2.la + +if USE_XVIDEO +xv_source = gstv4l2xoverlay.c +xv_libs = $(X_LIBS) $(XVIDEO_LIBS) +else +xv_source = +xv_libs = +endif + +libgstvideo4linux2_la_SOURCES = gstv4l2.c \ + gstv4l2colorbalance.c \ + gstv4l2object.c \ + gstv4l2bufferpool.c \ + gstv4l2src.c \ + gstv4l2radio.c \ + gstv4l2tuner.c \ + gstv4l2vidorient.c \ + v4l2_calls.c \ + v4l2src_calls.c \ + $(xv_source) + +if BUILD_EXPERIMENTAL +libgstvideo4linux2_la_SOURCES += gstv4l2sink.c +endif + +libgstvideo4linux2_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CONTROLLER_CFLAGS) \ + $(GST_CFLAGS) \ + $(X_CFLAGS) \ + $(LIBV4L2_CFLAGS) \ + $(GUDEV_CFLAGS) + +libgstvideo4linux2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstvideo4linux2_la_LIBTOOLFLAGS = --tag=disable-static + +libgstvideo4linux2_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ + $(GST_BASE_LIBS) \ + $(GST_CONTROLLER_LIBS) \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstvideo-$(GST_MAJORMINOR) \ + -lgstinterfaces-$(GST_MAJORMINOR) \ + $(GST_LIBS) \ + $(xv_libs) \ + $(LIBV4L2_LIBS) \ + $(GUDEV_LIBS) + +noinst_HEADERS = \ + gstv4l2bufferpool.h \ + gstv4l2colorbalance.h \ + gstv4l2object.h \ + gstv4l2sink.h \ + gstv4l2src.h \ + gstv4l2radio.h \ + gstv4l2tuner.h \ + gstv4l2vidorient.h \ + gstv4l2xoverlay.h \ + v4l2_calls.h \ + v4l2src_calls.h diff --git a/sys/v4l2/Makefile.in b/sys/v4l2/Makefile.in new file mode 100644 index 0000000..c9ad860 --- /dev/null +++ b/sys/v4l2/Makefile.in @@ -0,0 +1,953 @@ +# 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@ +@BUILD_EXPERIMENTAL_TRUE@am__append_1 = gstv4l2sink.c +subdir = sys/v4l2 +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 = +@USE_XVIDEO_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \ +@USE_XVIDEO_TRUE@ $(am__DEPENDENCIES_1) +libgstvideo4linux2_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am__libgstvideo4linux2_la_SOURCES_DIST = gstv4l2.c \ + gstv4l2colorbalance.c gstv4l2object.c gstv4l2bufferpool.c \ + gstv4l2src.c gstv4l2radio.c gstv4l2tuner.c gstv4l2vidorient.c \ + v4l2_calls.c v4l2src_calls.c gstv4l2xoverlay.c gstv4l2sink.c +@USE_XVIDEO_TRUE@am__objects_1 = \ +@USE_XVIDEO_TRUE@ libgstvideo4linux2_la-gstv4l2xoverlay.lo +@BUILD_EXPERIMENTAL_TRUE@am__objects_2 = \ +@BUILD_EXPERIMENTAL_TRUE@ libgstvideo4linux2_la-gstv4l2sink.lo +am_libgstvideo4linux2_la_OBJECTS = libgstvideo4linux2_la-gstv4l2.lo \ + libgstvideo4linux2_la-gstv4l2colorbalance.lo \ + libgstvideo4linux2_la-gstv4l2object.lo \ + libgstvideo4linux2_la-gstv4l2bufferpool.lo \ + libgstvideo4linux2_la-gstv4l2src.lo \ + libgstvideo4linux2_la-gstv4l2radio.lo \ + libgstvideo4linux2_la-gstv4l2tuner.lo \ + libgstvideo4linux2_la-gstv4l2vidorient.lo \ + libgstvideo4linux2_la-v4l2_calls.lo \ + libgstvideo4linux2_la-v4l2src_calls.lo $(am__objects_1) \ + $(am__objects_2) +libgstvideo4linux2_la_OBJECTS = $(am_libgstvideo4linux2_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +libgstvideo4linux2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) \ + $(libgstvideo4linux2_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 = $(libgstvideo4linux2_la_SOURCES) +DIST_SOURCES = $(am__libgstvideo4linux2_la_SOURCES_DIST) +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 = libgstvideo4linux2.la +@USE_XVIDEO_FALSE@xv_source = +@USE_XVIDEO_TRUE@xv_source = gstv4l2xoverlay.c +@USE_XVIDEO_FALSE@xv_libs = +@USE_XVIDEO_TRUE@xv_libs = $(X_LIBS) $(XVIDEO_LIBS) +libgstvideo4linux2_la_SOURCES = gstv4l2.c gstv4l2colorbalance.c \ + gstv4l2object.c gstv4l2bufferpool.c gstv4l2src.c \ + gstv4l2radio.c gstv4l2tuner.c gstv4l2vidorient.c v4l2_calls.c \ + v4l2src_calls.c $(xv_source) $(am__append_1) +libgstvideo4linux2_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CONTROLLER_CFLAGS) \ + $(GST_CFLAGS) \ + $(X_CFLAGS) \ + $(LIBV4L2_CFLAGS) \ + $(GUDEV_CFLAGS) + +libgstvideo4linux2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstvideo4linux2_la_LIBTOOLFLAGS = --tag=disable-static +libgstvideo4linux2_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ + $(GST_BASE_LIBS) \ + $(GST_CONTROLLER_LIBS) \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstvideo-$(GST_MAJORMINOR) \ + -lgstinterfaces-$(GST_MAJORMINOR) \ + $(GST_LIBS) \ + $(xv_libs) \ + $(LIBV4L2_LIBS) \ + $(GUDEV_LIBS) + +noinst_HEADERS = \ + gstv4l2bufferpool.h \ + gstv4l2colorbalance.h \ + gstv4l2object.h \ + gstv4l2sink.h \ + gstv4l2src.h \ + gstv4l2radio.h \ + gstv4l2tuner.h \ + gstv4l2vidorient.h \ + gstv4l2xoverlay.h \ + v4l2_calls.h \ + v4l2src_calls.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 sys/v4l2/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu sys/v4l2/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 +libgstvideo4linux2.la: $(libgstvideo4linux2_la_OBJECTS) $(libgstvideo4linux2_la_DEPENDENCIES) $(EXTRA_libgstvideo4linux2_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgstvideo4linux2_la_LINK) -rpath $(plugindir) $(libgstvideo4linux2_la_OBJECTS) $(libgstvideo4linux2_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstvideo4linux2_la-gstv4l2.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstvideo4linux2_la-gstv4l2bufferpool.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstvideo4linux2_la-gstv4l2colorbalance.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstvideo4linux2_la-gstv4l2object.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstvideo4linux2_la-gstv4l2radio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstvideo4linux2_la-gstv4l2sink.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstvideo4linux2_la-gstv4l2src.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstvideo4linux2_la-gstv4l2tuner.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstvideo4linux2_la-gstv4l2vidorient.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstvideo4linux2_la-gstv4l2xoverlay.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstvideo4linux2_la-v4l2_calls.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstvideo4linux2_la-v4l2src_calls.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 $@ $< + +libgstvideo4linux2_la-gstv4l2.lo: gstv4l2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -MT libgstvideo4linux2_la-gstv4l2.lo -MD -MP -MF $(DEPDIR)/libgstvideo4linux2_la-gstv4l2.Tpo -c -o libgstvideo4linux2_la-gstv4l2.lo `test -f 'gstv4l2.c' || echo '$(srcdir)/'`gstv4l2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstvideo4linux2_la-gstv4l2.Tpo $(DEPDIR)/libgstvideo4linux2_la-gstv4l2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstv4l2.c' object='libgstvideo4linux2_la-gstv4l2.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 $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -c -o libgstvideo4linux2_la-gstv4l2.lo `test -f 'gstv4l2.c' || echo '$(srcdir)/'`gstv4l2.c + +libgstvideo4linux2_la-gstv4l2colorbalance.lo: gstv4l2colorbalance.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -MT libgstvideo4linux2_la-gstv4l2colorbalance.lo -MD -MP -MF $(DEPDIR)/libgstvideo4linux2_la-gstv4l2colorbalance.Tpo -c -o libgstvideo4linux2_la-gstv4l2colorbalance.lo `test -f 'gstv4l2colorbalance.c' || echo '$(srcdir)/'`gstv4l2colorbalance.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstvideo4linux2_la-gstv4l2colorbalance.Tpo $(DEPDIR)/libgstvideo4linux2_la-gstv4l2colorbalance.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstv4l2colorbalance.c' object='libgstvideo4linux2_la-gstv4l2colorbalance.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 $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -c -o libgstvideo4linux2_la-gstv4l2colorbalance.lo `test -f 'gstv4l2colorbalance.c' || echo '$(srcdir)/'`gstv4l2colorbalance.c + +libgstvideo4linux2_la-gstv4l2object.lo: gstv4l2object.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -MT libgstvideo4linux2_la-gstv4l2object.lo -MD -MP -MF $(DEPDIR)/libgstvideo4linux2_la-gstv4l2object.Tpo -c -o libgstvideo4linux2_la-gstv4l2object.lo `test -f 'gstv4l2object.c' || echo '$(srcdir)/'`gstv4l2object.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstvideo4linux2_la-gstv4l2object.Tpo $(DEPDIR)/libgstvideo4linux2_la-gstv4l2object.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstv4l2object.c' object='libgstvideo4linux2_la-gstv4l2object.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 $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -c -o libgstvideo4linux2_la-gstv4l2object.lo `test -f 'gstv4l2object.c' || echo '$(srcdir)/'`gstv4l2object.c + +libgstvideo4linux2_la-gstv4l2bufferpool.lo: gstv4l2bufferpool.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -MT libgstvideo4linux2_la-gstv4l2bufferpool.lo -MD -MP -MF $(DEPDIR)/libgstvideo4linux2_la-gstv4l2bufferpool.Tpo -c -o libgstvideo4linux2_la-gstv4l2bufferpool.lo `test -f 'gstv4l2bufferpool.c' || echo '$(srcdir)/'`gstv4l2bufferpool.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstvideo4linux2_la-gstv4l2bufferpool.Tpo $(DEPDIR)/libgstvideo4linux2_la-gstv4l2bufferpool.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstv4l2bufferpool.c' object='libgstvideo4linux2_la-gstv4l2bufferpool.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 $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -c -o libgstvideo4linux2_la-gstv4l2bufferpool.lo `test -f 'gstv4l2bufferpool.c' || echo '$(srcdir)/'`gstv4l2bufferpool.c + +libgstvideo4linux2_la-gstv4l2src.lo: gstv4l2src.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -MT libgstvideo4linux2_la-gstv4l2src.lo -MD -MP -MF $(DEPDIR)/libgstvideo4linux2_la-gstv4l2src.Tpo -c -o libgstvideo4linux2_la-gstv4l2src.lo `test -f 'gstv4l2src.c' || echo '$(srcdir)/'`gstv4l2src.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstvideo4linux2_la-gstv4l2src.Tpo $(DEPDIR)/libgstvideo4linux2_la-gstv4l2src.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstv4l2src.c' object='libgstvideo4linux2_la-gstv4l2src.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 $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -c -o libgstvideo4linux2_la-gstv4l2src.lo `test -f 'gstv4l2src.c' || echo '$(srcdir)/'`gstv4l2src.c + +libgstvideo4linux2_la-gstv4l2radio.lo: gstv4l2radio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -MT libgstvideo4linux2_la-gstv4l2radio.lo -MD -MP -MF $(DEPDIR)/libgstvideo4linux2_la-gstv4l2radio.Tpo -c -o libgstvideo4linux2_la-gstv4l2radio.lo `test -f 'gstv4l2radio.c' || echo '$(srcdir)/'`gstv4l2radio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstvideo4linux2_la-gstv4l2radio.Tpo $(DEPDIR)/libgstvideo4linux2_la-gstv4l2radio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstv4l2radio.c' object='libgstvideo4linux2_la-gstv4l2radio.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 $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -c -o libgstvideo4linux2_la-gstv4l2radio.lo `test -f 'gstv4l2radio.c' || echo '$(srcdir)/'`gstv4l2radio.c + +libgstvideo4linux2_la-gstv4l2tuner.lo: gstv4l2tuner.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -MT libgstvideo4linux2_la-gstv4l2tuner.lo -MD -MP -MF $(DEPDIR)/libgstvideo4linux2_la-gstv4l2tuner.Tpo -c -o libgstvideo4linux2_la-gstv4l2tuner.lo `test -f 'gstv4l2tuner.c' || echo '$(srcdir)/'`gstv4l2tuner.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstvideo4linux2_la-gstv4l2tuner.Tpo $(DEPDIR)/libgstvideo4linux2_la-gstv4l2tuner.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstv4l2tuner.c' object='libgstvideo4linux2_la-gstv4l2tuner.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 $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -c -o libgstvideo4linux2_la-gstv4l2tuner.lo `test -f 'gstv4l2tuner.c' || echo '$(srcdir)/'`gstv4l2tuner.c + +libgstvideo4linux2_la-gstv4l2vidorient.lo: gstv4l2vidorient.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -MT libgstvideo4linux2_la-gstv4l2vidorient.lo -MD -MP -MF $(DEPDIR)/libgstvideo4linux2_la-gstv4l2vidorient.Tpo -c -o libgstvideo4linux2_la-gstv4l2vidorient.lo `test -f 'gstv4l2vidorient.c' || echo '$(srcdir)/'`gstv4l2vidorient.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstvideo4linux2_la-gstv4l2vidorient.Tpo $(DEPDIR)/libgstvideo4linux2_la-gstv4l2vidorient.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstv4l2vidorient.c' object='libgstvideo4linux2_la-gstv4l2vidorient.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 $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -c -o libgstvideo4linux2_la-gstv4l2vidorient.lo `test -f 'gstv4l2vidorient.c' || echo '$(srcdir)/'`gstv4l2vidorient.c + +libgstvideo4linux2_la-v4l2_calls.lo: v4l2_calls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -MT libgstvideo4linux2_la-v4l2_calls.lo -MD -MP -MF $(DEPDIR)/libgstvideo4linux2_la-v4l2_calls.Tpo -c -o libgstvideo4linux2_la-v4l2_calls.lo `test -f 'v4l2_calls.c' || echo '$(srcdir)/'`v4l2_calls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstvideo4linux2_la-v4l2_calls.Tpo $(DEPDIR)/libgstvideo4linux2_la-v4l2_calls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='v4l2_calls.c' object='libgstvideo4linux2_la-v4l2_calls.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 $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -c -o libgstvideo4linux2_la-v4l2_calls.lo `test -f 'v4l2_calls.c' || echo '$(srcdir)/'`v4l2_calls.c + +libgstvideo4linux2_la-v4l2src_calls.lo: v4l2src_calls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -MT libgstvideo4linux2_la-v4l2src_calls.lo -MD -MP -MF $(DEPDIR)/libgstvideo4linux2_la-v4l2src_calls.Tpo -c -o libgstvideo4linux2_la-v4l2src_calls.lo `test -f 'v4l2src_calls.c' || echo '$(srcdir)/'`v4l2src_calls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstvideo4linux2_la-v4l2src_calls.Tpo $(DEPDIR)/libgstvideo4linux2_la-v4l2src_calls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='v4l2src_calls.c' object='libgstvideo4linux2_la-v4l2src_calls.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 $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -c -o libgstvideo4linux2_la-v4l2src_calls.lo `test -f 'v4l2src_calls.c' || echo '$(srcdir)/'`v4l2src_calls.c + +libgstvideo4linux2_la-gstv4l2xoverlay.lo: gstv4l2xoverlay.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -MT libgstvideo4linux2_la-gstv4l2xoverlay.lo -MD -MP -MF $(DEPDIR)/libgstvideo4linux2_la-gstv4l2xoverlay.Tpo -c -o libgstvideo4linux2_la-gstv4l2xoverlay.lo `test -f 'gstv4l2xoverlay.c' || echo '$(srcdir)/'`gstv4l2xoverlay.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstvideo4linux2_la-gstv4l2xoverlay.Tpo $(DEPDIR)/libgstvideo4linux2_la-gstv4l2xoverlay.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstv4l2xoverlay.c' object='libgstvideo4linux2_la-gstv4l2xoverlay.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 $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -c -o libgstvideo4linux2_la-gstv4l2xoverlay.lo `test -f 'gstv4l2xoverlay.c' || echo '$(srcdir)/'`gstv4l2xoverlay.c + +libgstvideo4linux2_la-gstv4l2sink.lo: gstv4l2sink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -MT libgstvideo4linux2_la-gstv4l2sink.lo -MD -MP -MF $(DEPDIR)/libgstvideo4linux2_la-gstv4l2sink.Tpo -c -o libgstvideo4linux2_la-gstv4l2sink.lo `test -f 'gstv4l2sink.c' || echo '$(srcdir)/'`gstv4l2sink.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstvideo4linux2_la-gstv4l2sink.Tpo $(DEPDIR)/libgstvideo4linux2_la-gstv4l2sink.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstv4l2sink.c' object='libgstvideo4linux2_la-gstv4l2sink.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 $(libgstvideo4linux2_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstvideo4linux2_la_CFLAGS) $(CFLAGS) -c -o libgstvideo4linux2_la-gstv4l2sink.lo `test -f 'gstv4l2sink.c' || echo '$(srcdir)/'`gstv4l2sink.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/sys/v4l2/README b/sys/v4l2/README new file mode 100644 index 0000000..e9c4ab4 --- /dev/null +++ b/sys/v4l2/README @@ -0,0 +1,32 @@ +v4l2 plugins +============ + +The idea is a bit the same as the idea for the v4l1 plugins. We want +one generic v4l2element, and a few child objects (probably only two: +v4l2src and v4l2sink): + + /-------- v4l2src +v4l2element ---= + \-------- v4l2sink + +Both v4l2src and v4l2sink have a uncompressed and a compressed +recording-/playback-mode. Since this is all part of v4l2, the 'client' +of these elements, i.e. an application using v4l2src/v4l2sink, will +hardly notice this. All capsnego stuff is done inside, and the plugin +knows which formats are compressed and which are not. + +Please note that the v4l1 and the v4l2 plugins are *not* compatible +concerning properties. Naming has been kept the same where possible, +but in some cases, properties had to be removed or added to make +full use of v4l2. + +V4L2 API: http://linux.bytesex.org/v4l2/. + http://v4l2spec.bytesex.org/ + /usr/include/linux/videodev2.h or + +Kernel patches available from + http://dl.bytesex.org/patches/. + +Articles: + http://lwn.net/Articles/203924/ + diff --git a/sys/v4l2/gstv4l2.c b/sys/v4l2/gstv4l2.c new file mode 100644 index 0000000..95f64db --- /dev/null +++ b/sys/v4l2/gstv4l2.c @@ -0,0 +1,86 @@ +/* GStreamer + * + * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2.c: plugin for v4l2 elements + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gst/gst-i18n-plugin.h" + +#include <gst/gst.h> +#include <gst/controller/gstcontroller.h> + +#include "gstv4l2object.h" +#include "gstv4l2src.h" +#ifdef HAVE_EXPERIMENTAL +#include "gstv4l2sink.h" +#endif +#include "gstv4l2radio.h" +/* #include "gstv4l2jpegsrc.h" */ +/* #include "gstv4l2mjpegsrc.h" */ +/* #include "gstv4l2mjpegsink.h" */ + +/* used in v4l2_calls.c and v4l2src_calls.c */ +GST_DEBUG_CATEGORY (v4l2_debug); +GST_DEBUG_CATEGORY (GST_CAT_PERFORMANCE); + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (v4l2_debug, "v4l2", 0, "V4L2 API calls"); + GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE"); + + /* initialize gst controller library */ + gst_controller_init (NULL, NULL); + + if (!gst_element_register (plugin, "v4l2src", GST_RANK_PRIMARY, + GST_TYPE_V4L2SRC) || +#ifdef HAVE_EXPERIMENTAL + !gst_element_register (plugin, "v4l2sink", GST_RANK_NONE, + GST_TYPE_V4L2SINK) || +#endif + !gst_element_register (plugin, "v4l2radio", GST_RANK_NONE, + GST_TYPE_V4L2RADIO) || + /* !gst_element_register (plugin, "v4l2jpegsrc", */ + /* GST_RANK_NONE, GST_TYPE_V4L2JPEGSRC) || */ + /* !gst_element_register (plugin, "v4l2mjpegsrc", */ + /* GST_RANK_NONE, GST_TYPE_V4L2MJPEGSRC) || */ + /* !gst_element_register (plugin, "v4l2mjpegsink", */ + /* GST_RANK_NONE, GST_TYPE_V4L2MJPEGSINK)) */ + FALSE) + return FALSE; + +#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, + "video4linux2", + "elements for Video 4 Linux", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c new file mode 100644 index 0000000..b81c6a4 --- /dev/null +++ b/sys/v4l2/gstv4l2bufferpool.c @@ -0,0 +1,652 @@ +/* GStreamer + * + * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * 2009 Texas Instruments, Inc - http://www.ti.com/ + * + * gstv4l2bufferpool.c V4L2 buffer pool class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 <sys/mman.h> +#include <string.h> +#include <unistd.h> + +#include "gst/video/video.h" + +#include <gstv4l2bufferpool.h> +#include "gstv4l2src.h" +#ifdef HAVE_EXPERIMENTAL +#include "gstv4l2sink.h" +#endif +#include "v4l2_calls.h" +#include "gst/gst-i18n-plugin.h" +#include <gst/glib-compat-private.h> + +/* videodev2.h is not versioned and we can't easily check for the presence + * of enum values at compile time, but the V4L2_CAP_VIDEO_OUTPUT_OVERLAY define + * was added in the same commit as V4L2_FIELD_INTERLACED_{TB,BT} (b2787845) */ +#ifndef V4L2_CAP_VIDEO_OUTPUT_OVERLAY +#define V4L2_FIELD_INTERLACED_TB 8 +#define V4L2_FIELD_INTERLACED_BT 9 +#endif + + +GST_DEBUG_CATEGORY_EXTERN (v4l2_debug); +#define GST_CAT_DEFAULT v4l2_debug + + +/* + * GstV4l2Buffer: + */ + +static GstBufferClass *v4l2buffer_parent_class = NULL; + +static void +gst_v4l2_buffer_finalize (GstV4l2Buffer * buffer) +{ + GstV4l2BufferPool *pool; + gboolean resuscitated = FALSE; + gint index; + + pool = buffer->pool; + + index = buffer->vbuffer.index; + + GST_LOG_OBJECT (pool->v4l2elem, "finalizing buffer %p %d", buffer, index); + + GST_V4L2_BUFFER_POOL_LOCK (pool); + if (pool->running) { + if (pool->requeuebuf) { + if (!gst_v4l2_buffer_pool_qbuf (pool, buffer)) { + GST_WARNING ("could not requeue buffer %p %d", buffer, index); + } else { + resuscitated = TRUE; + } + } else { + resuscitated = TRUE; + /* XXX double check this... I think it is ok to not synchronize this + * w.r.t. destruction of the pool, since the buffer is still live and + * the buffer holds a ref to the pool.. + */ + g_async_queue_push (pool->avail_buffers, buffer); + } + } else { + GST_LOG_OBJECT (pool->v4l2elem, "the pool is shutting down"); + } + + if (resuscitated) { + /* FIXME: check that the caps didn't change */ + GST_LOG_OBJECT (pool->v4l2elem, "reviving buffer %p, %d", buffer, index); + gst_buffer_ref (GST_BUFFER (buffer)); + GST_BUFFER_SIZE (buffer) = 0; + pool->buffers[index] = buffer; + } + + GST_V4L2_BUFFER_POOL_UNLOCK (pool); + + if (!resuscitated) { + GST_LOG_OBJECT (pool->v4l2elem, + "buffer %p (data %p, len %u) not recovered, unmapping", + buffer, GST_BUFFER_DATA (buffer), buffer->vbuffer.length); + gst_mini_object_unref (GST_MINI_OBJECT (pool)); + v4l2_munmap ((void *) GST_BUFFER_DATA (buffer), buffer->vbuffer.length); + + GST_MINI_OBJECT_CLASS (v4l2buffer_parent_class)->finalize (GST_MINI_OBJECT + (buffer)); + } +} + +static void +gst_v4l2_buffer_class_init (gpointer g_class, gpointer class_data) +{ + GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class); + + v4l2buffer_parent_class = g_type_class_peek_parent (g_class); + + mini_object_class->finalize = (GstMiniObjectFinalizeFunction) + gst_v4l2_buffer_finalize; +} + +GType +gst_v4l2_buffer_get_type (void) +{ + static GType _gst_v4l2_buffer_type; + + if (G_UNLIKELY (_gst_v4l2_buffer_type == 0)) { + static const GTypeInfo v4l2_buffer_info = { + sizeof (GstBufferClass), + NULL, + NULL, + gst_v4l2_buffer_class_init, + NULL, + NULL, + sizeof (GstV4l2Buffer), + 0, + NULL, + NULL + }; + _gst_v4l2_buffer_type = g_type_register_static (GST_TYPE_BUFFER, + "GstV4l2Buffer", &v4l2_buffer_info, 0); + } + return _gst_v4l2_buffer_type; +} + +static GstV4l2Buffer * +gst_v4l2_buffer_new (GstV4l2BufferPool * pool, guint index, GstCaps * caps) +{ + GstV4l2Buffer *ret; + guint8 *data; + + ret = (GstV4l2Buffer *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER); + + GST_LOG_OBJECT (pool->v4l2elem, "creating buffer %u, %p in pool %p", index, + ret, pool); + + ret->pool = + (GstV4l2BufferPool *) gst_mini_object_ref (GST_MINI_OBJECT (pool)); + + ret->vbuffer.index = index; + ret->vbuffer.type = pool->type; + ret->vbuffer.memory = V4L2_MEMORY_MMAP; + + if (v4l2_ioctl (pool->video_fd, VIDIOC_QUERYBUF, &ret->vbuffer) < 0) + goto querybuf_failed; + + GST_LOG_OBJECT (pool->v4l2elem, " index: %u", ret->vbuffer.index); + GST_LOG_OBJECT (pool->v4l2elem, " type: %d", ret->vbuffer.type); + GST_LOG_OBJECT (pool->v4l2elem, " bytesused: %u", ret->vbuffer.bytesused); + GST_LOG_OBJECT (pool->v4l2elem, " flags: %08x", ret->vbuffer.flags); + GST_LOG_OBJECT (pool->v4l2elem, " field: %d", ret->vbuffer.field); + GST_LOG_OBJECT (pool->v4l2elem, " memory: %d", ret->vbuffer.memory); + if (ret->vbuffer.memory == V4L2_MEMORY_MMAP) + GST_LOG_OBJECT (pool->v4l2elem, " MMAP offset: %u", + ret->vbuffer.m.offset); + GST_LOG_OBJECT (pool->v4l2elem, " length: %u", ret->vbuffer.length); + GST_LOG_OBJECT (pool->v4l2elem, " input: %u", ret->vbuffer.input); + + data = (guint8 *) v4l2_mmap (0, ret->vbuffer.length, + PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd, + ret->vbuffer.m.offset); + + if (data == MAP_FAILED) + goto mmap_failed; + + GST_BUFFER_DATA (ret) = data; + GST_BUFFER_SIZE (ret) = ret->vbuffer.length; + + GST_BUFFER_FLAG_SET (ret, GST_BUFFER_FLAG_READONLY); + + gst_buffer_set_caps (GST_BUFFER (ret), caps); + + return ret; + + /* ERRORS */ +querybuf_failed: + { + gint errnosave = errno; + + GST_WARNING ("Failed QUERYBUF: %s", g_strerror (errnosave)); + gst_buffer_unref (GST_BUFFER (ret)); + errno = errnosave; + return NULL; + } +mmap_failed: + { + gint errnosave = errno; + + GST_WARNING ("Failed to mmap: %s", g_strerror (errnosave)); + gst_buffer_unref (GST_BUFFER (ret)); + errno = errnosave; + return NULL; + } +} + + +/* + * GstV4l2BufferPool: + */ + +static GstMiniObjectClass *buffer_pool_parent_class = NULL; + +static void +gst_v4l2_buffer_pool_finalize (GstV4l2BufferPool * pool) +{ + g_mutex_free (pool->lock); + pool->lock = NULL; + + g_async_queue_unref (pool->avail_buffers); + pool->avail_buffers = NULL; + + if (pool->video_fd >= 0) + v4l2_close (pool->video_fd); + + if (pool->buffers) { + g_free (pool->buffers); + pool->buffers = NULL; + } + + GST_MINI_OBJECT_CLASS (buffer_pool_parent_class)->finalize (GST_MINI_OBJECT + (pool)); +} + +static void +gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool, gpointer g_class) +{ + pool->lock = g_mutex_new (); + pool->running = FALSE; + pool->num_live_buffers = 0; +} + +static void +gst_v4l2_buffer_pool_class_init (gpointer g_class, gpointer class_data) +{ + GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class); + + buffer_pool_parent_class = g_type_class_peek_parent (g_class); + + mini_object_class->finalize = (GstMiniObjectFinalizeFunction) + gst_v4l2_buffer_pool_finalize; +} + +GType +gst_v4l2_buffer_pool_get_type (void) +{ + static GType _gst_v4l2_buffer_pool_type; + + if (G_UNLIKELY (_gst_v4l2_buffer_pool_type == 0)) { + static const GTypeInfo v4l2_buffer_pool_info = { + sizeof (GstMiniObjectClass), + NULL, + NULL, + gst_v4l2_buffer_pool_class_init, + NULL, + NULL, + sizeof (GstV4l2BufferPool), + 0, + (GInstanceInitFunc) gst_v4l2_buffer_pool_init, + NULL + }; + _gst_v4l2_buffer_pool_type = g_type_register_static (GST_TYPE_MINI_OBJECT, + "GstV4l2BufferPool", &v4l2_buffer_pool_info, 0); + } + return _gst_v4l2_buffer_pool_type; +} + + +/* this is somewhat of a hack.. but better to keep the hack in + * one place than copy/pasting it around.. + */ +static GstV4l2Object * +get_v4l2_object (GstElement * v4l2elem) +{ + GstV4l2Object *v4l2object = NULL; + if (GST_IS_V4L2SRC (v4l2elem)) { + v4l2object = (GST_V4L2SRC (v4l2elem))->v4l2object; +#ifdef HAVE_EXPERIMENTAL + } else if (GST_IS_V4L2SINK (v4l2elem)) { + v4l2object = (GST_V4L2SINK (v4l2elem))->v4l2object; +#endif + } else { + GST_ERROR_OBJECT (v4l2elem, "unknown v4l2 element"); + } + return v4l2object; +} + + + +/** + * gst_v4l2_buffer_pool_new: + * @v4l2elem: the v4l2 element (src or sink) that owns this pool + * @fd: the video device file descriptor + * @num_buffers: the requested number of buffers in the pool + * @caps: the caps to set on the buffer + * @requeuebuf: if %TRUE, and if the pool is still in the running state, a + * buffer with no remaining references is immediately passed back to v4l2 + * (VIDIOC_QBUF), otherwise it is returned to the pool of available buffers + * (which can be accessed via gst_v4l2_buffer_pool_get(). + * + * Construct a new buffer pool. + * + * Returns: the new pool, use gst_v4l2_buffer_pool_destroy() to free resources + */ +GstV4l2BufferPool * +gst_v4l2_buffer_pool_new (GstElement * v4l2elem, gint fd, gint num_buffers, + GstCaps * caps, gboolean requeuebuf, enum v4l2_buf_type type) +{ + GstV4l2BufferPool *pool; + gint n; + struct v4l2_requestbuffers breq; + + pool = (GstV4l2BufferPool *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER_POOL); + + pool->video_fd = v4l2_dup (fd); + if (pool->video_fd < 0) + goto dup_failed; + + + /* first, lets request buffers, and see how many we can get: */ + GST_DEBUG_OBJECT (v4l2elem, "STREAMING, requesting %d MMAP buffers", + num_buffers); + + memset (&breq, 0, sizeof (struct v4l2_requestbuffers)); + breq.type = type; + breq.count = num_buffers; + breq.memory = V4L2_MEMORY_MMAP; + + if (v4l2_ioctl (fd, VIDIOC_REQBUFS, &breq) < 0) + goto reqbufs_failed; + + GST_LOG_OBJECT (v4l2elem, " count: %u", breq.count); + GST_LOG_OBJECT (v4l2elem, " type: %d", breq.type); + GST_LOG_OBJECT (v4l2elem, " memory: %d", breq.memory); + + if (breq.count < GST_V4L2_MIN_BUFFERS) + goto no_buffers; + + if (num_buffers != breq.count) { + GST_WARNING_OBJECT (v4l2elem, "using %u buffers instead", breq.count); + num_buffers = breq.count; + } + + pool->v4l2elem = v4l2elem; + pool->requeuebuf = requeuebuf; + pool->type = type; + pool->buffer_count = num_buffers; + pool->buffers = g_new0 (GstV4l2Buffer *, num_buffers); + pool->avail_buffers = g_async_queue_new (); + + /* now, map the buffers: */ + for (n = 0; n < num_buffers; n++) { + pool->buffers[n] = gst_v4l2_buffer_new (pool, n, caps); + if (!pool->buffers[n]) + goto buffer_new_failed; + pool->num_live_buffers++; + g_async_queue_push (pool->avail_buffers, pool->buffers[n]); + } + + return pool; + + /* ERRORS */ +dup_failed: + { + gint errnosave = errno; + + gst_mini_object_unref (GST_MINI_OBJECT (pool)); + + errno = errnosave; + + return NULL; + } +reqbufs_failed: + { + GstV4l2Object *v4l2object = get_v4l2_object (v4l2elem); + GST_ELEMENT_ERROR (v4l2elem, RESOURCE, READ, + (_("Could not get buffers from device '%s'."), + v4l2object->videodev), + ("error requesting %d buffers: %s", num_buffers, g_strerror (errno))); + return NULL; + } +no_buffers: + { + GstV4l2Object *v4l2object = get_v4l2_object (v4l2elem); + GST_ELEMENT_ERROR (v4l2elem, RESOURCE, READ, + (_("Could not get enough buffers from device '%s'."), + v4l2object->videodev), + ("we received %d from device '%s', we want at least %d", + breq.count, v4l2object->videodev, GST_V4L2_MIN_BUFFERS)); + return NULL; + } +buffer_new_failed: + { + gint errnosave = errno; + + gst_v4l2_buffer_pool_destroy (pool); + + errno = errnosave; + + return NULL; + } +} + +/** + * gst_v4l2_buffer_pool_destroy: + * @pool: the pool + * + * Free all resources in the pool and the pool itself. + */ +void +gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool) +{ + gint n; + + GST_V4L2_BUFFER_POOL_LOCK (pool); + pool->running = FALSE; + GST_V4L2_BUFFER_POOL_UNLOCK (pool); + + GST_DEBUG_OBJECT (pool->v4l2elem, "destroy pool"); + + /* after this point, no more buffers will be queued or dequeued; no buffer + * from pool->buffers that is NULL will be set to a buffer, and no buffer that + * is not NULL will be pushed out. */ + + /* miniobjects have no dispose, so they can't break ref-cycles, as buffers ref + * the pool, we need to unref the buffer to properly finalize te pool */ + for (n = 0; n < pool->buffer_count; n++) { + GstBuffer *buf; + + GST_V4L2_BUFFER_POOL_LOCK (pool); + buf = GST_BUFFER (pool->buffers[n]); + GST_V4L2_BUFFER_POOL_UNLOCK (pool); + + if (buf) + /* we own the ref if the buffer is in pool->buffers; drop it. */ + gst_buffer_unref (buf); + } + + gst_mini_object_unref (GST_MINI_OBJECT (pool)); +} + +/** + * gst_v4l2_buffer_pool_get: + * @pool: the "this" object + * @blocking: should this call suspend until there is a buffer available + * in the buffer pool? + * + * Get an available buffer in the pool + */ +GstV4l2Buffer * +gst_v4l2_buffer_pool_get (GstV4l2BufferPool * pool, gboolean blocking) +{ + GstV4l2Buffer *buf; + + if (blocking) { + buf = g_async_queue_pop (pool->avail_buffers); + } else { + buf = g_async_queue_try_pop (pool->avail_buffers); + } + + if (buf) { + GST_V4L2_BUFFER_POOL_LOCK (pool); + GST_BUFFER_SIZE (buf) = buf->vbuffer.length; + GST_BUFFER_FLAG_UNSET (buf, 0xffffffff); + GST_V4L2_BUFFER_POOL_UNLOCK (pool); + } + + pool->running = TRUE; + + return buf; +} + + +/** + * gst_v4l2_buffer_pool_qbuf: + * @pool: the pool + * @buf: the buffer to queue + * + * Queue a buffer to the driver + * + * Returns: %TRUE for success + */ +gboolean +gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstV4l2Buffer * buf) +{ + GST_LOG_OBJECT (pool->v4l2elem, "enqueue pool buffer %d", buf->vbuffer.index); + + if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, &buf->vbuffer) < 0) + return FALSE; + + pool->num_live_buffers--; + GST_DEBUG_OBJECT (pool->v4l2elem, "num_live_buffers--: %d", + pool->num_live_buffers); + + return TRUE; +} + +/** + * gst_v4l2_buffer_pool_dqbuf: + * @pool: the pool + * + * Dequeue a buffer from the driver. Some generic error handling is done in + * this function, but any error handling specific to v4l2src (capture) or + * v4l2sink (output) can be done outside this function by checking 'errno' + * + * Returns: a buffer + */ +GstV4l2Buffer * +gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool) +{ + GstV4l2Object *v4l2object = get_v4l2_object (pool->v4l2elem); + GstV4l2Buffer *pool_buffer; + struct v4l2_buffer buffer; + + memset (&buffer, 0x00, sizeof (buffer)); + buffer.type = pool->type; + buffer.memory = V4L2_MEMORY_MMAP; + + + if (v4l2_ioctl (pool->video_fd, VIDIOC_DQBUF, &buffer) >= 0) { + + GST_V4L2_BUFFER_POOL_LOCK (pool); + + /* get our GstBuffer with that index from the pool, if the buffer was + * outstanding we have a serious problem. + */ + pool_buffer = pool->buffers[buffer.index]; + + if (pool_buffer == NULL) { + GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, + (_("Failed trying to get video frames from device '%s'."), + v4l2object->videodev), + (_("No free buffers found in the pool at index %d."), buffer.index)); + GST_V4L2_BUFFER_POOL_UNLOCK (pool); + return NULL; + } + + GST_LOG_OBJECT (pool->v4l2elem, + "grabbed frame %d (ix=%d), flags %08x, pool-ct=%d, buffer=%p", + buffer.sequence, buffer.index, buffer.flags, pool->num_live_buffers, + pool_buffer); + + pool->num_live_buffers++; + GST_DEBUG_OBJECT (pool->v4l2elem, "num_live_buffers++: %d", + pool->num_live_buffers); + + /* set top/bottom field first if v4l2_buffer has the information */ + if (buffer.field == V4L2_FIELD_INTERLACED_TB) + GST_BUFFER_FLAG_SET (pool_buffer, GST_VIDEO_BUFFER_TFF); + if (buffer.field == V4L2_FIELD_INTERLACED_BT) + GST_BUFFER_FLAG_UNSET (pool_buffer, GST_VIDEO_BUFFER_TFF); + + /* this can change at every frame, esp. with jpeg */ + GST_BUFFER_SIZE (pool_buffer) = buffer.bytesused; + + GST_V4L2_BUFFER_POOL_UNLOCK (pool); + + return pool_buffer; + } + + + GST_WARNING_OBJECT (pool->v4l2elem, + "problem grabbing frame %d (ix=%d), pool-ct=%d, buf.flags=%d", + buffer.sequence, buffer.index, + GST_MINI_OBJECT_REFCOUNT (pool), buffer.flags); + + switch (errno) { + case EAGAIN: + GST_WARNING_OBJECT (pool->v4l2elem, + "Non-blocking I/O has been selected using O_NONBLOCK and" + " no buffer was in the outgoing queue. device %s", + v4l2object->videodev); + break; + case EINVAL: + GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, + (_("Failed trying to get video frames from device '%s'."), + v4l2object->videodev), + (_("The buffer type is not supported, or the index is out of bounds," + " or no buffers have been allocated yet, or the userptr" + " or length are invalid. device %s"), v4l2object->videodev)); + break; + case ENOMEM: + GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, + (_("Failed trying to get video frames from device '%s'. Not enough memory."), v4l2object->videodev), (_("insufficient memory to enqueue a user pointer buffer. device %s."), v4l2object->videodev)); + break; + case EIO: + GST_INFO_OBJECT (pool->v4l2elem, + "VIDIOC_DQBUF failed due to an internal error." + " Can also indicate temporary problems like signal loss." + " Note the driver might dequeue an (empty) buffer despite" + " returning an error, or even stop capturing." + " device %s", v4l2object->videodev); + /* have we de-queued a buffer ? */ + if (!(buffer.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) { + GST_DEBUG_OBJECT (pool->v4l2elem, "reenqueing buffer"); + /* FIXME ... should we do something here? */ + } + break; + case EINTR: + GST_WARNING_OBJECT (pool->v4l2elem, + "could not sync on a buffer on device %s", v4l2object->videodev); + break; + default: + GST_WARNING_OBJECT (pool->v4l2elem, + "Grabbing frame got interrupted on %s unexpectedly. %d: %s.", + v4l2object->videodev, errno, g_strerror (errno)); + break; + } + + return NULL; +} + +/** + * gst_v4l2_buffer_pool_available_buffers: + * @pool: the pool + * + * Check the number of buffers available to the driver, ie. buffers that + * have been QBUF'd but not yet DQBUF'd. + * + * Returns: the number of buffers available. + */ +gint +gst_v4l2_buffer_pool_available_buffers (GstV4l2BufferPool * pool) +{ + return pool->buffer_count - pool->num_live_buffers; +} diff --git a/sys/v4l2/gstv4l2bufferpool.h b/sys/v4l2/gstv4l2bufferpool.h new file mode 100644 index 0000000..caad9ac --- /dev/null +++ b/sys/v4l2/gstv4l2bufferpool.h @@ -0,0 +1,97 @@ +/* GStreamer + * + * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * 2009 Texas Instruments, Inc - http://www.ti.com/ + * + * gstv4l2bufferpool.h V4L2 buffer pool class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 __GSTV4L2BUFFER_H__ +#define __GSTV4L2BUFFER_H__ + +#include <gst/gst.h> +#include "v4l2_calls.h" + +GST_DEBUG_CATEGORY_EXTERN (v4l2buffer_debug); + +G_BEGIN_DECLS + + +GType gst_v4l2_buffer_get_type (void); +#define GST_TYPE_V4L2_BUFFER (gst_v4l2_buffer_get_type()) +#define GST_IS_V4L2_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_BUFFER)) +#define GST_V4L2_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_BUFFER, GstV4l2Buffer)) + +GType gst_v4l2_buffer_pool_get_type (void); +#define GST_TYPE_V4L2_BUFFER_POOL (gst_v4l2_buffer_pool_get_type()) +#define GST_IS_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_BUFFER_POOL)) +#define GST_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_BUFFER_POOL, GstV4l2BufferPool)) + + + +typedef struct _GstV4l2BufferPool GstV4l2BufferPool; +typedef struct _GstV4l2Buffer GstV4l2Buffer; + + +struct _GstV4l2BufferPool +{ + GstMiniObject parent; + + GstElement *v4l2elem; /* the v4l2 src/sink that owns us.. maybe we should be owned by v4l2object? */ + gboolean requeuebuf; /* if true, unusued buffers are automatically re-QBUF'd */ + enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT */ + + GMutex *lock; + gboolean running; /* with lock */ + gint num_live_buffers; /* number of buffers not with driver */ + GAsyncQueue* avail_buffers;/* pool of available buffers, not with the driver and which aren't held outside the bufferpool */ + gint video_fd; /* a dup(2) of the v4l2object's video_fd */ + guint buffer_count; + GstV4l2Buffer **buffers; +}; + +struct _GstV4l2Buffer { + GstBuffer buffer; + + struct v4l2_buffer vbuffer; + + /* FIXME: have GstV4l2Src* instead, as this has GstV4l2BufferPool* */ + /* FIXME: do we really want to fix this if GstV4l2Buffer/Pool is shared + * between v4l2src and v4l2sink?? + */ + GstV4l2BufferPool *pool; +}; + +void gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool); +GstV4l2BufferPool *gst_v4l2_buffer_pool_new (GstElement *v4l2elem, gint fd, gint num_buffers, GstCaps * caps, gboolean requeuebuf, enum v4l2_buf_type type); + + +GstV4l2Buffer *gst_v4l2_buffer_pool_get (GstV4l2BufferPool *pool, gboolean blocking); +gboolean gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool *pool, GstV4l2Buffer *buf); +GstV4l2Buffer *gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool *pool); + +gint gst_v4l2_buffer_pool_available_buffers (GstV4l2BufferPool *pool); + + +#define GST_V4L2_BUFFER_POOL_LOCK(pool) g_mutex_lock ((pool)->lock) +#define GST_V4L2_BUFFER_POOL_UNLOCK(pool) g_mutex_unlock ((pool)->lock) + +G_END_DECLS + +#endif /* __GSTV4L2BUFFER_H__ */ diff --git a/sys/v4l2/gstv4l2colorbalance.c b/sys/v4l2/gstv4l2colorbalance.c new file mode 100644 index 0000000..f5cde09 --- /dev/null +++ b/sys/v4l2/gstv4l2colorbalance.c @@ -0,0 +1,106 @@ +/* GStreamer + * + * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2colorbalance.c: color balance interface implementation for V4L2 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 "gstv4l2colorbalance.h" +#include "gstv4l2object.h" + +GST_BOILERPLATE (GstV4l2ColorBalanceChannel, + gst_v4l2_color_balance_channel, + GstColorBalanceChannel, GST_TYPE_COLOR_BALANCE_CHANNEL); + +static void +gst_v4l2_color_balance_channel_base_init (gpointer g_class) +{ +} + +static void +gst_v4l2_color_balance_channel_class_init (GstV4l2ColorBalanceChannelClass * + klass) +{ +} + +static void +gst_v4l2_color_balance_channel_init (GstV4l2ColorBalanceChannel * channel, + GstV4l2ColorBalanceChannelClass * klass) +{ + channel->id = (guint32) - 1; +} + +static G_GNUC_UNUSED gboolean +gst_v4l2_color_balance_contains_channel (GstV4l2Object * v4l2object, + GstV4l2ColorBalanceChannel * v4l2channel) +{ + const GList *item; + + for (item = v4l2object->colors; item != NULL; item = item->next) + if (item->data == v4l2channel) + return TRUE; + + return FALSE; +} + +const GList * +gst_v4l2_color_balance_list_channels (GstV4l2Object * v4l2object) +{ + return v4l2object->colors; +} + +void +gst_v4l2_color_balance_set_value (GstV4l2Object * v4l2object, + GstColorBalanceChannel * channel, gint value) +{ + + GstV4l2ColorBalanceChannel *v4l2channel = + GST_V4L2_COLOR_BALANCE_CHANNEL (channel); + + /* assert that we're opened and that we're using a known item */ + g_return_if_fail (GST_V4L2_IS_OPEN (v4l2object)); + g_return_if_fail (gst_v4l2_color_balance_contains_channel (v4l2object, + v4l2channel)); + + gst_v4l2_set_attribute (v4l2object, v4l2channel->id, value); +} + +gint +gst_v4l2_color_balance_get_value (GstV4l2Object * v4l2object, + GstColorBalanceChannel * channel) +{ + GstV4l2ColorBalanceChannel *v4l2channel = + GST_V4L2_COLOR_BALANCE_CHANNEL (channel); + gint value; + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), 0); + g_return_val_if_fail (gst_v4l2_color_balance_contains_channel (v4l2object, + v4l2channel), 0); + + if (!gst_v4l2_get_attribute (v4l2object, v4l2channel->id, &value)) + return 0; + + return value; +} diff --git a/sys/v4l2/gstv4l2colorbalance.h b/sys/v4l2/gstv4l2colorbalance.h new file mode 100644 index 0000000..9e183f0 --- /dev/null +++ b/sys/v4l2/gstv4l2colorbalance.h @@ -0,0 +1,104 @@ +/* GStreamer + * + * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2colorbalance.h: color balance interface implementation for V4L2 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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_V4L2_COLOR_BALANCE_H__ +#define __GST_V4L2_COLOR_BALANCE_H__ + +#include <gst/gst.h> +#include <gst/interfaces/colorbalance.h> +#include "v4l2_calls.h" + +G_BEGIN_DECLS + +#define GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL \ + (gst_v4l2_color_balance_channel_get_type ()) +#define GST_V4L2_COLOR_BALANCE_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, \ + GstV4l2ColorBalanceChannel)) +#define GST_V4L2_COLOR_BALANCE_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, \ + GstV4l2ColorBalanceChannelClass)) +#define GST_IS_V4L2_COLOR_BALANCE_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL)) +#define GST_IS_V4L2_COLOR_BALANCE_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL)) + +typedef struct _GstV4l2ColorBalanceChannel { + GstColorBalanceChannel parent; + + guint32 id; +} GstV4l2ColorBalanceChannel; + +typedef struct _GstV4l2ColorBalanceChannelClass { + GstColorBalanceChannelClass parent; +} GstV4l2ColorBalanceChannelClass; + +GType gst_v4l2_color_balance_channel_get_type (void); + +const GList * gst_v4l2_color_balance_list_channels (GstV4l2Object * v4l2object); + +void gst_v4l2_color_balance_set_value (GstV4l2Object * v4l2object, + GstColorBalanceChannel * channel, + gint value); + +gint gst_v4l2_color_balance_get_value (GstV4l2Object * v4l2object, + GstColorBalanceChannel * channel); + +#define GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS(Type, interface_as_function) \ + \ +static const GList * \ +interface_as_function ## _color_balance_list_channels (GstColorBalance * balance) \ +{ \ + Type *this = (Type*) balance; \ + return gst_v4l2_color_balance_list_channels(this->v4l2object); \ +} \ + \ +static void \ +interface_as_function ## _color_balance_set_value (GstColorBalance * balance, \ + GstColorBalanceChannel * channel, \ + gint value) \ +{ \ + Type *this = (Type*) balance; \ + gst_v4l2_color_balance_set_value(this->v4l2object, channel, value); \ +} \ + \ +static gint \ +interface_as_function ## _color_balance_get_value (GstColorBalance * balance, \ + GstColorBalanceChannel * channel) \ +{ \ + Type *this = (Type*) balance; \ + return gst_v4l2_color_balance_get_value(this->v4l2object, channel); \ +} \ + \ +static void \ +interface_as_function ## _color_balance_interface_init (GstColorBalanceClass * klass) \ +{ \ + GST_COLOR_BALANCE_TYPE (klass) = GST_COLOR_BALANCE_HARDWARE; \ + \ + /* default virtual functions */ \ + klass->list_channels = interface_as_function ## _color_balance_list_channels; \ + klass->set_value = interface_as_function ## _color_balance_set_value; \ + klass->get_value = interface_as_function ## _color_balance_get_value; \ +} \ + +#endif /* __GST_V4L2_COLOR_BALANCE_H__ */ diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c new file mode 100644 index 0000000..81d1cb7 --- /dev/null +++ b/sys/v4l2/gstv4l2object.c @@ -0,0 +1,2247 @@ +/* GStreamer + * + * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2object.c: base class for V4L2 elements + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. This library is distributed in the hope + * that it will be useful, but WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU Library General Public License for more details. + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> + +#ifdef HAVE_GUDEV +#include <gudev/gudev.h> +#endif + +#include "v4l2_calls.h" +#include "gstv4l2tuner.h" +#ifdef HAVE_XVIDEO +#include "gstv4l2xoverlay.h" +#endif +#include "gstv4l2colorbalance.h" + +#include "gst/gst-i18n-plugin.h" + +/* videodev2.h is not versioned and we can't easily check for the presence + * of enum values at compile time, but the V4L2_CAP_VIDEO_OUTPUT_OVERLAY define + * was added in the same commit as V4L2_FIELD_INTERLACED_{TB,BT} (b2787845) */ +#ifndef V4L2_CAP_VIDEO_OUTPUT_OVERLAY +#define V4L2_FIELD_INTERLACED_TB 8 +#define V4L2_FIELD_INTERLACED_BT 9 +#endif + +GST_DEBUG_CATEGORY_EXTERN (v4l2_debug); +#define GST_CAT_DEFAULT v4l2_debug + + +#define DEFAULT_PROP_DEVICE_NAME NULL +#define DEFAULT_PROP_DEVICE_FD -1 +#define DEFAULT_PROP_FLAGS 0 +#define DEFAULT_PROP_TV_NORM 0 +#define DEFAULT_PROP_CHANNEL NULL +#define DEFAULT_PROP_FREQUENCY 0 + +enum +{ + PROP_0, + V4L2_STD_OBJECT_PROPS, +}; + +G_LOCK_DEFINE_STATIC (probe_lock); + +const GList * +gst_v4l2_probe_get_properties (GstPropertyProbe * probe) +{ + GObjectClass *klass = G_OBJECT_GET_CLASS (probe); + static GList *list = NULL; + + /* well, not perfect, but better than no locking at all. + * In the worst case we leak a list node, so who cares? */ + G_LOCK (probe_lock); + + if (!list) { + list = g_list_append (NULL, g_object_class_find_property (klass, "device")); + } + + G_UNLOCK (probe_lock); + + return list; +} + +static gboolean init = FALSE; +static GList *devices = NULL; + +#ifdef HAVE_GUDEV +static gboolean +gst_v4l2_class_probe_devices_with_udev (GstElementClass * klass, gboolean check, + GList ** klass_devices) +{ + GUdevClient *client = NULL; + GList *item; + + if (!check) { + while (devices) { + gchar *device = devices->data; + devices = g_list_remove (devices, device); + g_free (device); + } + + GST_INFO ("Enumerating video4linux devices from udev"); + client = g_udev_client_new (NULL); + if (!client) { + GST_WARNING ("Failed to initialize gudev client"); + goto finish; + } + + item = g_udev_client_query_by_subsystem (client, "video4linux"); + while (item) { + GUdevDevice *device = item->data; + gchar *devnode = g_strdup (g_udev_device_get_device_file (device)); + gint api = g_udev_device_get_property_as_int (device, "ID_V4L_VERSION"); + GST_INFO ("Found new device: %s, API: %d", devnode, api); + /* Append v4l2 devices only. If api is 0 probably v4l_id has + been stripped out of the current udev installation, append + anyway */ + if (api == 0) { + GST_WARNING + ("Couldn't retrieve ID_V4L_VERSION, silly udev installation?"); + } + if ((api == 2 || api == 0)) { + devices = g_list_append (devices, devnode); + } else { + g_free (devnode); + } + g_object_unref (device); + item = item->next; + } + g_list_free (item); + init = TRUE; + } + +finish: + if (client) { + g_object_unref (client); + } + + *klass_devices = devices; + + return init; +} +#endif /* HAVE_GUDEV */ + +static gboolean +gst_v4l2_class_probe_devices (GstElementClass * klass, gboolean check, + GList ** klass_devices) +{ + if (!check) { + const gchar *dev_base[] = { "/dev/video", "/dev/v4l2/video", NULL }; + gint base, n, fd; + + while (devices) { + gchar *device = devices->data; + devices = g_list_remove (devices, device); + g_free (device); + } + + /* + * detect /dev entries + */ + for (n = 0; n < 64; n++) { + for (base = 0; dev_base[base] != NULL; base++) { + struct stat s; + gchar *device = g_strdup_printf ("%s%d", + dev_base[base], + n); + + /* + * does the /dev/ entry exist at all? + */ + if (stat (device, &s) == 0) { + /* + * yes: is a device attached? + */ + if (S_ISCHR (s.st_mode)) { + + if ((fd = open (device, O_RDWR | O_NONBLOCK)) > 0 || errno == EBUSY) { + if (fd > 0) + close (fd); + + devices = g_list_append (devices, device); + break; + } + } + } + g_free (device); + } + } + init = TRUE; + } + + *klass_devices = devices; + + return init; +} + +void +gst_v4l2_probe_probe_property (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec, GList ** klass_devices) +{ + GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe); + + switch (prop_id) { + case PROP_DEVICE: +#ifdef HAVE_GUDEV + if (!gst_v4l2_class_probe_devices_with_udev (klass, FALSE, klass_devices)) + gst_v4l2_class_probe_devices (klass, FALSE, klass_devices); +#else /* !HAVE_GUDEV */ + gst_v4l2_class_probe_devices (klass, FALSE, klass_devices); +#endif /* HAVE_GUDEV */ + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } +} + +gboolean +gst_v4l2_probe_needs_probe (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec, GList ** klass_devices) +{ + GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe); + gboolean ret = FALSE; + + switch (prop_id) { + case PROP_DEVICE: +#ifdef HAVE_GUDEV + ret = + !gst_v4l2_class_probe_devices_with_udev (klass, FALSE, klass_devices); +#else /* !HAVE_GUDEV */ + ret = !gst_v4l2_class_probe_devices (klass, TRUE, klass_devices); +#endif /* HAVE_GUDEV */ + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + return ret; +} + +static GValueArray * +gst_v4l2_class_list_devices (GstElementClass * klass, GList ** klass_devices) +{ + GValueArray *array; + GValue value = { 0 }; + GList *item; + + if (!*klass_devices) + return NULL; + + array = g_value_array_new (g_list_length (*klass_devices)); + item = *klass_devices; + g_value_init (&value, G_TYPE_STRING); + while (item) { + gchar *device = item->data; + + g_value_set_string (&value, device); + g_value_array_append (array, &value); + + item = item->next; + } + g_value_unset (&value); + + return array; +} + +GValueArray * +gst_v4l2_probe_get_values (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec, GList ** klass_devices) +{ + GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe); + GValueArray *array = NULL; + + switch (prop_id) { + case PROP_DEVICE: + array = gst_v4l2_class_list_devices (klass, klass_devices); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + + return array; +} + +#define GST_TYPE_V4L2_DEVICE_FLAGS (gst_v4l2_device_get_type ()) +static GType +gst_v4l2_device_get_type (void) +{ + static GType v4l2_device_type = 0; + + if (v4l2_device_type == 0) { + static const GFlagsValue values[] = { + {V4L2_CAP_VIDEO_CAPTURE, "Device supports video capture", "capture"}, + {V4L2_CAP_VIDEO_OUTPUT, "Device supports video playback", "output"}, + {V4L2_CAP_VIDEO_OVERLAY, "Device supports video overlay", "overlay"}, + + {V4L2_CAP_VBI_CAPTURE, "Device supports the VBI capture", "vbi-capture"}, + {V4L2_CAP_VBI_OUTPUT, "Device supports the VBI output", "vbi-output"}, + + {V4L2_CAP_TUNER, "Device has a tuner or modulator", "tuner"}, + {V4L2_CAP_AUDIO, "Device has audio inputs or outputs", "audio"}, + + {0, NULL, NULL} + }; + + v4l2_device_type = + g_flags_register_static ("GstV4l2DeviceTypeFlags", values); + } + + return v4l2_device_type; +} + +#define GST_TYPE_V4L2_TV_NORM (gst_v4l2_tv_norm_get_type ()) +static GType +gst_v4l2_tv_norm_get_type (void) +{ + static GType v4l2_tv_norm = 0; + + if (!v4l2_tv_norm) { + static const GEnumValue tv_norms[] = { + {0, "none", "none"}, + + {V4L2_STD_NTSC, "NTSC", "NTSC"}, + {V4L2_STD_NTSC_M, "NTSC-M", "NTSC-M"}, + {V4L2_STD_NTSC_M_JP, "NTSC-M-JP", "NTSC-M-JP"}, + {V4L2_STD_NTSC_M_KR, "NTSC-M-KR", "NTSC-M-KR"}, + {V4L2_STD_NTSC_443, "NTSC-443", "NTSC-443"}, + + {V4L2_STD_PAL, "PAL", "PAL"}, + {V4L2_STD_PAL_BG, "PAL-BG", "PAL-BG"}, + {V4L2_STD_PAL_B, "PAL-B", "PAL-B"}, + {V4L2_STD_PAL_B1, "PAL-B1", "PAL-B1"}, + {V4L2_STD_PAL_G, "PAL-G", "PAL-G"}, + {V4L2_STD_PAL_H, "PAL-H", "PAL-H"}, + {V4L2_STD_PAL_I, "PAL-I", "PAL-I"}, + {V4L2_STD_PAL_DK, "PAL-DK", "PAL-DK"}, + {V4L2_STD_PAL_D, "PAL-D", "PAL-D"}, + {V4L2_STD_PAL_D1, "PAL-D1", "PAL-D1"}, + {V4L2_STD_PAL_K, "PAL-K", "PAL-K"}, + {V4L2_STD_PAL_M, "PAL-M", "PAL-M"}, + {V4L2_STD_PAL_N, "PAL-N", "PAL-N"}, + {V4L2_STD_PAL_Nc, "PAL-Nc", "PAL-Nc"}, + {V4L2_STD_PAL_60, "PAL-60", "PAL-60"}, + + {V4L2_STD_SECAM, "SECAM", "SECAM"}, + {V4L2_STD_SECAM_B, "SECAM-B", "SECAM-B"}, + {V4L2_STD_SECAM_G, "SECAM-G", "SECAM-G"}, + {V4L2_STD_SECAM_H, "SECAM-H", "SECAM-H"}, + {V4L2_STD_SECAM_DK, "SECAM-DK", "SECAM-DK"}, + {V4L2_STD_SECAM_D, "SECAM-D", "SECAM-D"}, + {V4L2_STD_SECAM_K, "SECAM-K", "SECAM-K"}, + {V4L2_STD_SECAM_K1, "SECAM-K1", "SECAM-K1"}, + {V4L2_STD_SECAM_L, "SECAM-L", "SECAM-L"}, + {V4L2_STD_SECAM_LC, "SECAM-Lc", "SECAM-Lc"}, + + {0, NULL, NULL} + }; + + v4l2_tv_norm = g_enum_register_static ("V4L2_TV_norms", tv_norms); + } + + return v4l2_tv_norm; +} + +void +gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class, + const char *default_device) +{ + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", "Device location", + 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", + "Name of the device", DEFAULT_PROP_DEVICE_NAME, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DEVICE_FD, + g_param_spec_int ("device-fd", "File descriptor", + "File descriptor of the device", -1, G_MAXINT, DEFAULT_PROP_DEVICE_FD, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_FLAGS, + g_param_spec_flags ("flags", "Flags", "Device type flags", + GST_TYPE_V4L2_DEVICE_FLAGS, DEFAULT_PROP_FLAGS, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + /** + * GstV4l2Src:brightness + * + * Picture brightness, or more precisely, the black level + * + * Since: 0.10.26 + */ + g_object_class_install_property (gobject_class, PROP_BRIGHTNESS, + g_param_spec_int ("brightness", "Brightness", + "Picture brightness, or more precisely, the black level", G_MININT, + G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE)); + /** + * GstV4l2Src:contrast + * + * Picture contrast or luma gain + * + * Since: 0.10.26 + */ + g_object_class_install_property (gobject_class, PROP_CONTRAST, + g_param_spec_int ("contrast", "Contrast", + "Picture contrast or luma gain", G_MININT, + G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE)); + /** + * GstV4l2Src:saturation + * + * Picture color saturation or chroma gain + * + * Since: 0.10.26 + */ + g_object_class_install_property (gobject_class, PROP_SATURATION, + g_param_spec_int ("saturation", "Saturation", + "Picture color saturation or chroma gain", G_MININT, + G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE)); + /** + * GstV4l2Src:hue + * + * Hue or color balance + * + * Since: 0.10.26 + */ + g_object_class_install_property (gobject_class, PROP_HUE, + g_param_spec_int ("hue", "Hue", + "Hue or color balance", G_MININT, + G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE)); + + /** + * GstV4l2Src:norm + * + * TV norm + * + * Since: 0.10.31 + */ + g_object_class_install_property (gobject_class, PROP_TV_NORM, + g_param_spec_enum ("norm", "TV norm", + "video standard", + GST_TYPE_V4L2_TV_NORM, DEFAULT_PROP_TV_NORM, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +GstV4l2Object * +gst_v4l2_object_new (GstElement * element, + enum v4l2_buf_type type, + const char *default_device, + GstV4l2GetInOutFunction get_in_out_func, + GstV4l2SetInOutFunction set_in_out_func, + GstV4l2UpdateFpsFunction update_fps_func) +{ + GstV4l2Object *v4l2object; + + /* + * some default values + */ + v4l2object = g_new0 (GstV4l2Object, 1); + + v4l2object->type = type; + v4l2object->formats = NULL; + + v4l2object->element = element; + v4l2object->get_in_out_func = get_in_out_func; + v4l2object->set_in_out_func = set_in_out_func; + v4l2object->update_fps_func = update_fps_func; + + v4l2object->video_fd = -1; + v4l2object->poll = gst_poll_new (TRUE); + v4l2object->buffer = NULL; + v4l2object->videodev = g_strdup (default_device); + + v4l2object->norms = NULL; + v4l2object->channels = NULL; + v4l2object->colors = NULL; + + v4l2object->xwindow_id = 0; + + return v4l2object; +} + +static gboolean gst_v4l2_object_clear_format_list (GstV4l2Object * v4l2object); + + +void +gst_v4l2_object_destroy (GstV4l2Object * v4l2object) +{ + g_return_if_fail (v4l2object != NULL); + + if (v4l2object->videodev) + g_free (v4l2object->videodev); + + if (v4l2object->poll) + gst_poll_free (v4l2object->poll); + + if (v4l2object->channel) + g_free (v4l2object->channel); + + if (v4l2object->formats) { + gst_v4l2_object_clear_format_list (v4l2object); + } + + g_free (v4l2object); +} + + +static gboolean +gst_v4l2_object_clear_format_list (GstV4l2Object * v4l2object) +{ + g_slist_foreach (v4l2object->formats, (GFunc) g_free, NULL); + g_slist_free (v4l2object->formats); + v4l2object->formats = NULL; + + return TRUE; +} + +static gint +gst_v4l2_object_prop_to_cid (guint prop_id) +{ + gint cid = -1; + + switch (prop_id) { + case PROP_BRIGHTNESS: + cid = V4L2_CID_BRIGHTNESS; + break; + case PROP_CONTRAST: + cid = V4L2_CID_CONTRAST; + break; + case PROP_SATURATION: + cid = V4L2_CID_SATURATION; + break; + case PROP_HUE: + cid = V4L2_CID_HUE; + break; + default: + GST_WARNING ("unmapped property id: %d", prop_id); + } + return cid; +} + + +gboolean +gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + switch (prop_id) { + case PROP_DEVICE: + g_free (v4l2object->videodev); + v4l2object->videodev = g_value_dup_string (value); + break; + case PROP_BRIGHTNESS: + case PROP_CONTRAST: + case PROP_SATURATION: + case PROP_HUE: + { + gint cid = gst_v4l2_object_prop_to_cid (prop_id); + + if (cid != -1) { + if (GST_V4L2_IS_OPEN (v4l2object)) { + gst_v4l2_set_attribute (v4l2object, cid, g_value_get_int (value)); + } + } + return TRUE; + } + break; + case PROP_TV_NORM: + v4l2object->tv_norm = g_value_get_enum (value); + break; +#if 0 + case PROP_CHANNEL: + if (GST_V4L2_IS_OPEN (v4l2object)) { + GstTuner *tuner = GST_TUNER (v4l2object->element); + GstTunerChannel *channel = gst_tuner_find_channel_by_name (tuner, + (gchar *) g_value_get_string (value)); + + if (channel) { + /* like gst_tuner_set_channel (tuner, channel) + without g_object_notify */ + gst_v4l2_tuner_set_channel (v4l2object, channel); + } + } else { + g_free (v4l2object->channel); + v4l2object->channel = g_value_dup_string (value); + } + break; + case PROP_FREQUENCY: + if (GST_V4L2_IS_OPEN (v4l2object)) { + GstTuner *tuner = GST_TUNER (v4l2object->element); + GstTunerChannel *channel = gst_tuner_get_channel (tuner); + + if (channel && + GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { + /* like + gst_tuner_set_frequency (tuner, channel, g_value_get_ulong (value)) + without g_object_notify */ + gst_v4l2_tuner_set_frequency (v4l2object, channel, + g_value_get_ulong (value)); + } + } else { + v4l2object->frequency = g_value_get_ulong (value); + } + break; +#endif + default: + return FALSE; + break; + } + return TRUE; +} + + +gboolean +gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + switch (prop_id) { + case PROP_DEVICE: + g_value_set_string (value, v4l2object->videodev); + break; + case PROP_DEVICE_NAME: + { + const guchar *new = NULL; + + if (GST_V4L2_IS_OPEN (v4l2object)) { + new = v4l2object->vcap.card; + } else if (gst_v4l2_open (v4l2object)) { + new = v4l2object->vcap.card; + gst_v4l2_close (v4l2object); + } + g_value_set_string (value, (gchar *) new); + break; + } + case PROP_DEVICE_FD: + { + if (GST_V4L2_IS_OPEN (v4l2object)) + g_value_set_int (value, v4l2object->video_fd); + else + g_value_set_int (value, DEFAULT_PROP_DEVICE_FD); + break; + } + case PROP_FLAGS: + { + guint flags = 0; + + if (GST_V4L2_IS_OPEN (v4l2object)) { + flags |= v4l2object->vcap.capabilities & + (V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_VBI_OUTPUT | V4L2_CAP_TUNER | V4L2_CAP_AUDIO); + } + g_value_set_flags (value, flags); + break; + } + case PROP_BRIGHTNESS: + case PROP_CONTRAST: + case PROP_SATURATION: + case PROP_HUE: + { + gint cid = gst_v4l2_object_prop_to_cid (prop_id); + + if (cid != -1) { + if (GST_V4L2_IS_OPEN (v4l2object)) { + gint v; + if (gst_v4l2_get_attribute (v4l2object, cid, &v)) { + g_value_set_int (value, v); + } + } + } + return TRUE; + } + break; + case PROP_TV_NORM: + g_value_set_enum (value, v4l2object->tv_norm); + break; + default: + return FALSE; + break; + } + return TRUE; +} + +static void +gst_v4l2_set_defaults (GstV4l2Object * v4l2object) +{ + GstTunerNorm *norm = NULL; + GstTunerChannel *channel = NULL; + GstTuner *tuner; + + if (!GST_IS_TUNER (v4l2object->element)) + return; + + tuner = GST_TUNER (v4l2object->element); + + if (v4l2object->tv_norm) + norm = gst_v4l2_tuner_get_norm_by_std_id (v4l2object, v4l2object->tv_norm); + GST_DEBUG_OBJECT (v4l2object->element, "tv_norm=0x%" G_GINT64_MODIFIER "x, " + "norm=%p", (guint64) v4l2object->tv_norm, norm); + if (norm) { + gst_tuner_set_norm (tuner, norm); + } else { + norm = + GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2object->element))); + if (norm) { + v4l2object->tv_norm = + gst_v4l2_tuner_get_std_id_by_norm (v4l2object, norm); + gst_tuner_norm_changed (tuner, norm); + } + } + + if (v4l2object->channel) + channel = gst_tuner_find_channel_by_name (tuner, v4l2object->channel); + if (channel) { + gst_tuner_set_channel (tuner, channel); + } else { + channel = + GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER + (v4l2object->element))); + if (channel) { + g_free (v4l2object->channel); + v4l2object->channel = g_strdup (channel->label); + gst_tuner_channel_changed (tuner, channel); + } + } + + if (channel + && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { + if (v4l2object->frequency != 0) { + gst_tuner_set_frequency (tuner, channel, v4l2object->frequency); + } else { + v4l2object->frequency = gst_tuner_get_frequency (tuner, channel); + if (v4l2object->frequency == 0) { + /* guess */ + gst_tuner_set_frequency (tuner, channel, 1000); + } else { + } + } + } +} + +gboolean +gst_v4l2_object_start (GstV4l2Object * v4l2object) +{ + if (gst_v4l2_open (v4l2object)) + gst_v4l2_set_defaults (v4l2object); + else + return FALSE; + +#ifdef HAVE_XVIDEO + gst_v4l2_xoverlay_start (v4l2object); +#endif + + return TRUE; +} + +gboolean +gst_v4l2_object_stop (GstV4l2Object * v4l2object) +{ +#ifdef HAVE_XVIDEO + gst_v4l2_xoverlay_stop (v4l2object); +#endif + + if (!gst_v4l2_close (v4l2object)) + return FALSE; + + if (v4l2object->formats) { + gst_v4l2_object_clear_format_list (v4l2object); + } + + return TRUE; +} + + +/* + * common format / caps utilities: + */ +typedef struct +{ + guint32 format; + gboolean dimensions; +} GstV4L2FormatDesc; + +static const GstV4L2FormatDesc gst_v4l2_formats[] = { + /* from Linux 2.6.15 videodev2.h */ + {V4L2_PIX_FMT_RGB332, TRUE}, + {V4L2_PIX_FMT_RGB555, TRUE}, + {V4L2_PIX_FMT_RGB565, TRUE}, + {V4L2_PIX_FMT_RGB555X, TRUE}, + {V4L2_PIX_FMT_RGB565X, TRUE}, + {V4L2_PIX_FMT_BGR24, TRUE}, + {V4L2_PIX_FMT_RGB24, TRUE}, + {V4L2_PIX_FMT_BGR32, TRUE}, + {V4L2_PIX_FMT_RGB32, TRUE}, + {V4L2_PIX_FMT_GREY, TRUE}, + {V4L2_PIX_FMT_YVU410, TRUE}, + {V4L2_PIX_FMT_YVU420, TRUE}, + {V4L2_PIX_FMT_YUYV, TRUE}, + {V4L2_PIX_FMT_UYVY, TRUE}, + {V4L2_PIX_FMT_YUV422P, TRUE}, + {V4L2_PIX_FMT_YUV411P, TRUE}, + {V4L2_PIX_FMT_Y41P, TRUE}, + + /* two planes -- one Y, one Cr + Cb interleaved */ + {V4L2_PIX_FMT_NV12, TRUE}, + {V4L2_PIX_FMT_NV21, TRUE}, + + /* The following formats are not defined in the V4L2 specification */ + {V4L2_PIX_FMT_YUV410, TRUE}, + {V4L2_PIX_FMT_YUV420, TRUE}, + {V4L2_PIX_FMT_YYUV, TRUE}, + {V4L2_PIX_FMT_HI240, TRUE}, + + /* see http://www.siliconimaging.com/RGB%20Bayer.htm */ +#ifdef V4L2_PIX_FMT_SBGGR8 + {V4L2_PIX_FMT_SBGGR8, TRUE}, +#endif + + /* compressed formats */ + {V4L2_PIX_FMT_MJPEG, TRUE}, + {V4L2_PIX_FMT_JPEG, TRUE}, +#ifdef V4L2_PIX_FMT_PJPG + {V4L2_PIX_FMT_PJPG, TRUE}, +#endif + {V4L2_PIX_FMT_DV, TRUE}, + {V4L2_PIX_FMT_MPEG, FALSE}, + + /* Vendor-specific formats */ + {V4L2_PIX_FMT_WNVA, TRUE}, + +#ifdef V4L2_PIX_FMT_SN9C10X + {V4L2_PIX_FMT_SN9C10X, TRUE}, +#endif +#ifdef V4L2_PIX_FMT_PWC1 + {V4L2_PIX_FMT_PWC1, TRUE}, +#endif +#ifdef V4L2_PIX_FMT_PWC2 + {V4L2_PIX_FMT_PWC2, TRUE}, +#endif +#ifdef V4L2_PIX_FMT_YVYU + {V4L2_PIX_FMT_YVYU, TRUE}, +#endif +}; + +#define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats)) + + +static struct v4l2_fmtdesc * +gst_v4l2_object_get_format_from_fourcc (GstV4l2Object * v4l2object, + guint32 fourcc) +{ + struct v4l2_fmtdesc *fmt; + GSList *walk; + + if (fourcc == 0) + return NULL; + + walk = gst_v4l2_object_get_format_list (v4l2object); + while (walk) { + fmt = (struct v4l2_fmtdesc *) walk->data; + if (fmt->pixelformat == fourcc) + return fmt; + /* special case for jpeg */ + if (fmt->pixelformat == V4L2_PIX_FMT_MJPEG || + fmt->pixelformat == V4L2_PIX_FMT_JPEG +#ifdef V4L2_PIX_FMT_PJPG + || fmt->pixelformat == V4L2_PIX_FMT_PJPG +#endif + ) { + if (fourcc == V4L2_PIX_FMT_JPEG || fourcc == V4L2_PIX_FMT_MJPEG +#ifdef V4L2_PIX_FMT_PJPG + || fourcc == V4L2_PIX_FMT_PJPG +#endif + ) { + return fmt; + } + } + walk = g_slist_next (walk); + } + + return NULL; +} + + + +/* complete made up ranking, the values themselves are meaningless */ +/* These ranks MUST be X such that X<<15 fits on a signed int - see + the comment at the end of gst_v4l2_object_format_get_rank. */ +#define YUV_BASE_RANK 1000 +#define JPEG_BASE_RANK 500 +#define DV_BASE_RANK 200 +#define RGB_BASE_RANK 100 +#define YUV_ODD_BASE_RANK 50 +#define RGB_ODD_BASE_RANK 25 +#define BAYER_BASE_RANK 15 +#define S910_BASE_RANK 10 +#define GREY_BASE_RANK 5 +#define PWC_BASE_RANK 1 + +/* This flag is already used by libv4l2 although + * it was added to the Linux kernel in 2.6.32 + */ +#ifndef V4L2_FMT_FLAG_EMULATED +#define V4L2_FMT_FLAG_EMULATED 0x0002 +#endif + +static gint +gst_v4l2_object_format_get_rank (const struct v4l2_fmtdesc *fmt) +{ + guint32 fourcc = fmt->pixelformat; + gboolean emulated = ((fmt->flags & V4L2_FMT_FLAG_EMULATED) != 0); + gint rank = 0; + + switch (fourcc) { + case V4L2_PIX_FMT_MJPEG: +#ifdef V4L2_PIX_FMT_PJPG + case V4L2_PIX_FMT_PJPG: + rank = JPEG_BASE_RANK; + break; +#endif + case V4L2_PIX_FMT_JPEG: + rank = JPEG_BASE_RANK + 1; + break; + case V4L2_PIX_FMT_MPEG: /* MPEG */ + rank = JPEG_BASE_RANK + 2; + break; + + case V4L2_PIX_FMT_RGB332: + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + rank = RGB_ODD_BASE_RANK; + break; + + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + rank = RGB_BASE_RANK - 1; + break; + + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32: + rank = RGB_BASE_RANK; + break; + + case V4L2_PIX_FMT_GREY: /* 8 Greyscale */ + rank = GREY_BASE_RANK; + break; + + case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */ + case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */ + case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */ + case V4L2_PIX_FMT_HI240: /* 8 8-bit color */ + rank = YUV_ODD_BASE_RANK; + break; + + case V4L2_PIX_FMT_YVU410: /* YVU9, 9 bits per pixel */ + rank = YUV_BASE_RANK + 3; + break; + case V4L2_PIX_FMT_YUV410: /* YUV9, 9 bits per pixel */ + rank = YUV_BASE_RANK + 2; + break; + case V4L2_PIX_FMT_YUV420: /* I420, 12 bits per pixel */ + rank = YUV_BASE_RANK + 7; + break; + case V4L2_PIX_FMT_YUYV: /* YUY2, 16 bits per pixel */ + rank = YUV_BASE_RANK + 10; + break; + case V4L2_PIX_FMT_YVU420: /* YV12, 12 bits per pixel */ + rank = YUV_BASE_RANK + 6; + break; + case V4L2_PIX_FMT_UYVY: /* UYVY, 16 bits per pixel */ + rank = YUV_BASE_RANK + 9; + break; + case V4L2_PIX_FMT_Y41P: /* Y41P, 12 bits per pixel */ + rank = YUV_BASE_RANK + 5; + break; + case V4L2_PIX_FMT_YUV411P: /* Y41B, 12 bits per pixel */ + rank = YUV_BASE_RANK + 4; + break; + case V4L2_PIX_FMT_YUV422P: /* Y42B, 16 bits per pixel */ + rank = YUV_BASE_RANK + 8; + break; + + case V4L2_PIX_FMT_DV: + rank = DV_BASE_RANK; + break; + + case V4L2_PIX_FMT_WNVA: /* Winnov hw compres */ + rank = 0; + break; + +#ifdef V4L2_PIX_FMT_SBGGR8 + case V4L2_PIX_FMT_SBGGR8: + rank = BAYER_BASE_RANK; + break; +#endif + +#ifdef V4L2_PIX_FMT_SN9C10X + case V4L2_PIX_FMT_SN9C10X: + rank = S910_BASE_RANK; + break; +#endif + +#ifdef V4L2_PIX_FMT_PWC1 + case V4L2_PIX_FMT_PWC1: + rank = PWC_BASE_RANK; + break; +#endif +#ifdef V4L2_PIX_FMT_PWC2 + case V4L2_PIX_FMT_PWC2: + rank = PWC_BASE_RANK; + break; +#endif + + default: + rank = 0; + break; + } + + /* All ranks are below 1<<15 so a shift by 15 + * will a) make all non-emulated formats larger + * than emulated and b) will not overflow + */ + if (!emulated) + rank <<= 15; + + return rank; +} + + + +static gint +format_cmp_func (gconstpointer a, gconstpointer b) +{ + const struct v4l2_fmtdesc *fa = a; + const struct v4l2_fmtdesc *fb = b; + + if (fa->pixelformat == fb->pixelformat) + return 0; + + return gst_v4l2_object_format_get_rank (fb) - + gst_v4l2_object_format_get_rank (fa); +} + +/****************************************************** + * gst_v4l2_object_fill_format_list(): + * create list of supported capture formats + * return value: TRUE on success, FALSE on error + ******************************************************/ +static gboolean +gst_v4l2_object_fill_format_list (GstV4l2Object * v4l2object) +{ + gint n; + struct v4l2_fmtdesc *format; + + GST_DEBUG_OBJECT (v4l2object->element, "getting src format enumerations"); + + /* format enumeration */ + for (n = 0;; n++) { + format = g_new0 (struct v4l2_fmtdesc, 1); + + format->index = n; + format->type = v4l2object->type; + + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) { + if (errno == EINVAL) { + g_free (format); + break; /* end of enumeration */ + } else { + goto failed; + } + } + + GST_LOG_OBJECT (v4l2object->element, "index: %u", format->index); + GST_LOG_OBJECT (v4l2object->element, "type: %d", format->type); + GST_LOG_OBJECT (v4l2object->element, "flags: %08x", format->flags); + GST_LOG_OBJECT (v4l2object->element, "description: '%s'", + format->description); + GST_LOG_OBJECT (v4l2object->element, "pixelformat: %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (format->pixelformat)); + + /* sort formats according to our preference; we do this, because caps + * are probed in the order the formats are in the list, and the order of + * formats in the final probed caps matters for things like fixation */ + v4l2object->formats = g_slist_insert_sorted (v4l2object->formats, format, + (GCompareFunc) format_cmp_func); + } + +#ifndef GST_DISABLE_GST_DEBUG + { + GSList *l; + + GST_INFO_OBJECT (v4l2object->element, "got %d format(s):", n); + for (l = v4l2object->formats; l != NULL; l = l->next) { + format = l->data; + + GST_INFO_OBJECT (v4l2object->element, + " %" GST_FOURCC_FORMAT "%s", GST_FOURCC_ARGS (format->pixelformat), + ((format->flags & V4L2_FMT_FLAG_EMULATED)) ? " (emulated)" : ""); + } + } +#endif + + return TRUE; + + /* ERRORS */ +failed: + { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to enumerate possible video formats device '%s' can work with"), v4l2object->videodev), ("Failed to get number %d in pixelformat enumeration for %s. (%d - %s)", n, v4l2object->videodev, errno, g_strerror (errno))); + g_free (format); + return FALSE; + } +} + +/* + * Get the list of supported capture formats, a list of + * <code>struct v4l2_fmtdesc</code>. + */ +GSList * +gst_v4l2_object_get_format_list (GstV4l2Object * v4l2object) +{ + if (!v4l2object->formats) + gst_v4l2_object_fill_format_list (v4l2object); + return v4l2object->formats; +} + + +GstStructure * +gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc) +{ + GstStructure *structure = NULL; + + switch (fourcc) { + case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */ +#ifdef V4L2_PIX_FMT_PJPG + case V4L2_PIX_FMT_PJPG: /* Progressive-JPEG */ +#endif + case V4L2_PIX_FMT_JPEG: /* JFIF JPEG */ + structure = gst_structure_new ("image/jpeg", NULL); + break; + case V4L2_PIX_FMT_RGB332: + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32:{ + guint depth = 0, bpp = 0; + + gint endianness = 0; + + guint32 r_mask = 0, b_mask = 0, g_mask = 0; + + switch (fourcc) { + case V4L2_PIX_FMT_RGB332: + bpp = depth = 8; + endianness = G_BYTE_ORDER; /* 'like, whatever' */ + r_mask = 0xe0; + g_mask = 0x1c; + b_mask = 0x03; + break; + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_RGB555X: + bpp = 16; + depth = 15; + endianness = + fourcc == V4L2_PIX_FMT_RGB555X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN; + r_mask = 0x7c00; + g_mask = 0x03e0; + b_mask = 0x001f; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + bpp = depth = 16; + endianness = + fourcc == V4L2_PIX_FMT_RGB565X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN; + r_mask = 0xf800; + g_mask = 0x07e0; + b_mask = 0x001f; + break; + case V4L2_PIX_FMT_RGB24: + bpp = depth = 24; + endianness = G_BIG_ENDIAN; + r_mask = 0xff0000; + g_mask = 0x00ff00; + b_mask = 0x0000ff; + break; + case V4L2_PIX_FMT_BGR24: + bpp = depth = 24; + endianness = G_BIG_ENDIAN; + r_mask = 0x0000ff; + g_mask = 0x00ff00; + b_mask = 0xff0000; + break; + case V4L2_PIX_FMT_RGB32: + bpp = depth = 32; + endianness = G_BIG_ENDIAN; + r_mask = 0xff000000; + g_mask = 0x00ff0000; + b_mask = 0x0000ff00; + break; + case V4L2_PIX_FMT_BGR32: + bpp = depth = 32; + endianness = G_BIG_ENDIAN; + r_mask = 0x000000ff; + g_mask = 0x0000ff00; + b_mask = 0x00ff0000; + break; + default: + g_assert_not_reached (); + break; + } + structure = gst_structure_new ("video/x-raw-rgb", + "bpp", G_TYPE_INT, bpp, + "depth", G_TYPE_INT, depth, + "red_mask", G_TYPE_INT, r_mask, + "green_mask", G_TYPE_INT, g_mask, + "blue_mask", G_TYPE_INT, b_mask, + "endianness", G_TYPE_INT, endianness, NULL); + break; + } + case V4L2_PIX_FMT_GREY: /* 8 Greyscale */ + structure = gst_structure_new ("video/x-raw-gray", + "bpp", G_TYPE_INT, 8, NULL); + break; + case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */ + case V4L2_PIX_FMT_HI240: /* 8 8-bit color */ + /* FIXME: get correct fourccs here */ + break; + case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */ + case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */ + case V4L2_PIX_FMT_YVU410: + case V4L2_PIX_FMT_YUV410: + case V4L2_PIX_FMT_YUV420: /* I420/IYUV */ + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_Y41P: + case V4L2_PIX_FMT_YUV422P: +#ifdef V4L2_PIX_FMT_YVYU + case V4L2_PIX_FMT_YVYU: +#endif + case V4L2_PIX_FMT_YUV411P:{ + guint32 fcc = 0; + + switch (fourcc) { + case V4L2_PIX_FMT_NV12: + fcc = GST_MAKE_FOURCC ('N', 'V', '1', '2'); + break; + case V4L2_PIX_FMT_NV21: + fcc = GST_MAKE_FOURCC ('N', 'V', '2', '1'); + break; + case V4L2_PIX_FMT_YVU410: + fcc = GST_MAKE_FOURCC ('Y', 'V', 'U', '9'); + break; + case V4L2_PIX_FMT_YUV410: + fcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9'); + break; + case V4L2_PIX_FMT_YUV420: + fcc = GST_MAKE_FOURCC ('I', '4', '2', '0'); + break; + case V4L2_PIX_FMT_YUYV: + fcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'); + break; + case V4L2_PIX_FMT_YVU420: + fcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2'); + break; + case V4L2_PIX_FMT_UYVY: + fcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'); + break; + case V4L2_PIX_FMT_Y41P: + fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P'); + break; + case V4L2_PIX_FMT_YUV411P: + fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B'); + break; + case V4L2_PIX_FMT_YUV422P: + fcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B'); + break; +#ifdef V4L2_PIX_FMT_YVYU + case V4L2_PIX_FMT_YVYU: + fcc = GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U'); + break; +#endif + default: + g_assert_not_reached (); + break; + } + structure = gst_structure_new ("video/x-raw-yuv", + "format", GST_TYPE_FOURCC, fcc, NULL); + break; + } + case V4L2_PIX_FMT_DV: + structure = + gst_structure_new ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE, + NULL); + break; + case V4L2_PIX_FMT_MPEG: /* MPEG */ + structure = gst_structure_new ("video/mpegts", NULL); + break; + case V4L2_PIX_FMT_WNVA: /* Winnov hw compres */ + break; +#ifdef V4L2_PIX_FMT_SBGGR8 + case V4L2_PIX_FMT_SBGGR8: + structure = gst_structure_new ("video/x-raw-bayer", NULL); + break; +#endif +#ifdef V4L2_PIX_FMT_SN9C10X + case V4L2_PIX_FMT_SN9C10X: + structure = gst_structure_new ("video/x-sonix", NULL); + break; +#endif +#ifdef V4L2_PIX_FMT_PWC1 + case V4L2_PIX_FMT_PWC1: + structure = gst_structure_new ("video/x-pwc1", NULL); + break; +#endif +#ifdef V4L2_PIX_FMT_PWC2 + case V4L2_PIX_FMT_PWC2: + structure = gst_structure_new ("video/x-pwc2", NULL); + break; +#endif + default: + GST_DEBUG ("Unknown fourcc 0x%08x %" GST_FOURCC_FORMAT, + fourcc, GST_FOURCC_ARGS (fourcc)); + break; + } + + return structure; +} + + + +GstCaps * +gst_v4l2_object_get_all_caps (void) +{ + static GstCaps *caps = NULL; + + if (caps == NULL) { + GstStructure *structure; + + guint i; + + caps = gst_caps_new_empty (); + for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) { + structure = + gst_v4l2_object_v4l2fourcc_to_structure (gst_v4l2_formats[i].format); + if (structure) { + if (gst_v4l2_formats[i].dimensions) { + gst_structure_set (structure, + "width", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE, + "height", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 100, 1, NULL); + } + gst_caps_append_structure (caps, structure); + } + } + } + + return gst_caps_ref (caps); +} + + +/* collect data for the given caps + * @caps: given input caps + * @format: location for the v4l format + * @w/@h: location for width and height + * @fps_n/@fps_d: location for framerate + * @size: location for expected size of the frame or 0 if unknown + */ +gboolean +gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps, + struct v4l2_fmtdesc ** format, gint * w, gint * h, + gboolean * interlaced, guint * fps_n, guint * fps_d, guint * size) +{ + GstStructure *structure; + const GValue *framerate; + guint32 fourcc; + const gchar *mimetype; + guint outsize; + + /* default unknown values */ + fourcc = 0; + outsize = 0; + + structure = gst_caps_get_structure (caps, 0); + + mimetype = gst_structure_get_name (structure); + + if (strcmp (mimetype, "video/mpegts") == 0) { + fourcc = V4L2_PIX_FMT_MPEG; + *fps_n = 0; + *fps_d = 1; + goto done; + } + + if (!gst_structure_get_int (structure, "width", w)) + return FALSE; + + if (!gst_structure_get_int (structure, "height", h)) + return FALSE; + + if (!gst_structure_get_boolean (structure, "interlaced", interlaced)) + *interlaced = FALSE; + + framerate = gst_structure_get_value (structure, "framerate"); + if (!framerate) + return FALSE; + + *fps_n = gst_value_get_fraction_numerator (framerate); + *fps_d = gst_value_get_fraction_denominator (framerate); + + if (!strcmp (mimetype, "video/x-raw-yuv")) { + gst_structure_get_fourcc (structure, "format", &fourcc); + + switch (fourcc) { + case GST_MAKE_FOURCC ('I', '4', '2', '0'): + case GST_MAKE_FOURCC ('I', 'Y', 'U', 'V'): + fourcc = V4L2_PIX_FMT_YUV420; + outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h); + outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * (GST_ROUND_UP_2 (*h) / 2)); + break; + case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): + fourcc = V4L2_PIX_FMT_YUYV; + outsize = (GST_ROUND_UP_2 (*w) * 2) * *h; + break; + case GST_MAKE_FOURCC ('Y', '4', '1', 'P'): + fourcc = V4L2_PIX_FMT_Y41P; + outsize = (GST_ROUND_UP_2 (*w) * 2) * *h; + break; + case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): + fourcc = V4L2_PIX_FMT_UYVY; + outsize = (GST_ROUND_UP_2 (*w) * 2) * *h; + break; + case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): + fourcc = V4L2_PIX_FMT_YVU420; + outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h); + outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * (GST_ROUND_UP_2 (*h) / 2)); + break; + case GST_MAKE_FOURCC ('Y', '4', '1', 'B'): + fourcc = V4L2_PIX_FMT_YUV411P; + outsize = GST_ROUND_UP_4 (*w) * *h; + outsize += 2 * ((GST_ROUND_UP_8 (*w) / 4) * *h); + break; + case GST_MAKE_FOURCC ('Y', '4', '2', 'B'): + fourcc = V4L2_PIX_FMT_YUV422P; + outsize = GST_ROUND_UP_4 (*w) * *h; + outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * *h); + break; + case GST_MAKE_FOURCC ('N', 'V', '1', '2'): + fourcc = V4L2_PIX_FMT_NV12; + outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h); + outsize += (GST_ROUND_UP_4 (*w) * *h) / 2; + break; + case GST_MAKE_FOURCC ('N', 'V', '2', '1'): + fourcc = V4L2_PIX_FMT_NV21; + outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h); + outsize += (GST_ROUND_UP_4 (*w) * *h) / 2; + break; +#ifdef V4L2_PIX_FMT_YVYU + case GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U'): + fourcc = V4L2_PIX_FMT_YVYU; + outsize = (GST_ROUND_UP_2 (*w) * 2) * *h; + break; +#endif + } + } else if (!strcmp (mimetype, "video/x-raw-rgb")) { + gint depth, endianness, r_mask; + + gst_structure_get_int (structure, "depth", &depth); + gst_structure_get_int (structure, "endianness", &endianness); + gst_structure_get_int (structure, "red_mask", &r_mask); + + switch (depth) { + case 8: + fourcc = V4L2_PIX_FMT_RGB332; + break; + case 15: + fourcc = (endianness == G_LITTLE_ENDIAN) ? + V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB555X; + break; + case 16: + fourcc = (endianness == G_LITTLE_ENDIAN) ? + V4L2_PIX_FMT_RGB565 : V4L2_PIX_FMT_RGB565X; + break; + case 24: + fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR24 : V4L2_PIX_FMT_RGB24; + break; + case 32: + fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR32 : V4L2_PIX_FMT_RGB32; + break; + } + } else if (strcmp (mimetype, "video/x-dv") == 0) { + fourcc = V4L2_PIX_FMT_DV; + } else if (strcmp (mimetype, "image/jpeg") == 0) { + fourcc = V4L2_PIX_FMT_JPEG; +#ifdef V4L2_PIX_FMT_SBGGR8 + } else if (strcmp (mimetype, "video/x-raw-bayer") == 0) { + fourcc = V4L2_PIX_FMT_SBGGR8; +#endif +#ifdef V4L2_PIX_FMT_SN9C10X + } else if (strcmp (mimetype, "video/x-sonix") == 0) { + fourcc = V4L2_PIX_FMT_SN9C10X; +#endif +#ifdef V4L2_PIX_FMT_PWC1 + } else if (strcmp (mimetype, "video/x-pwc1") == 0) { + fourcc = V4L2_PIX_FMT_PWC1; +#endif +#ifdef V4L2_PIX_FMT_PWC2 + } else if (strcmp (mimetype, "video/x-pwc2") == 0) { + fourcc = V4L2_PIX_FMT_PWC2; +#endif + } else if (strcmp (mimetype, "video/x-raw-gray") == 0) { + fourcc = V4L2_PIX_FMT_GREY; + } + + if (fourcc == 0) + return FALSE; + +done: + *format = gst_v4l2_object_get_format_from_fourcc (v4l2object, fourcc); + *size = outsize; + + return TRUE; +} + + +static gboolean +gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object, + guint32 pixelformat, gint * width, gint * height, gboolean * interlaced); + + +/* The frame interval enumeration code first appeared in Linux 2.6.19. */ +#ifdef VIDIOC_ENUM_FRAMEINTERVALS +static GstStructure * +gst_v4l2_object_probe_caps_for_format_and_size (GstV4l2Object * v4l2object, + guint32 pixelformat, + guint32 width, guint32 height, const GstStructure * template) +{ + gint fd = v4l2object->video_fd; + struct v4l2_frmivalenum ival; + guint32 num, denom; + GstStructure *s; + GValue rates = { 0, }; + gboolean interlaced; + gint int_width = width; + gint int_height = height; + + /* interlaced detection using VIDIOC_TRY/S_FMT */ + if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat, + &int_width, &int_height, &interlaced)) + return NULL; + + memset (&ival, 0, sizeof (struct v4l2_frmivalenum)); + ival.index = 0; + ival.pixel_format = pixelformat; + ival.width = width; + ival.height = height; + + GST_LOG_OBJECT (v4l2object->element, + "get frame interval for %ux%u, %" GST_FOURCC_FORMAT, width, height, + GST_FOURCC_ARGS (pixelformat)); + + /* keep in mind that v4l2 gives us frame intervals (durations); we invert the + * fraction to get framerate */ + if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0) + goto enum_frameintervals_failed; + + if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) { + GValue rate = { 0, }; + + g_value_init (&rates, GST_TYPE_LIST); + g_value_init (&rate, GST_TYPE_FRACTION); + + do { + num = ival.discrete.numerator; + denom = ival.discrete.denominator; + + if (num > G_MAXINT || denom > G_MAXINT) { + /* let us hope we don't get here... */ + num >>= 1; + denom >>= 1; + } + + GST_LOG_OBJECT (v4l2object->element, "adding discrete framerate: %d/%d", + denom, num); + + /* swap to get the framerate */ + gst_value_set_fraction (&rate, denom, num); + gst_value_list_append_value (&rates, &rate); + + ival.index++; + } while (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0); + } else if (ival.type == V4L2_FRMIVAL_TYPE_STEPWISE) { + GValue min = { 0, }; + GValue step = { 0, }; + GValue max = { 0, }; + gboolean added = FALSE; + guint32 minnum, mindenom; + guint32 maxnum, maxdenom; + + g_value_init (&rates, GST_TYPE_LIST); + + g_value_init (&min, GST_TYPE_FRACTION); + g_value_init (&step, GST_TYPE_FRACTION); + g_value_init (&max, GST_TYPE_FRACTION); + + /* get the min */ + minnum = ival.stepwise.min.numerator; + mindenom = ival.stepwise.min.denominator; + if (minnum > G_MAXINT || mindenom > G_MAXINT) { + minnum >>= 1; + mindenom >>= 1; + } + GST_LOG_OBJECT (v4l2object->element, "stepwise min frame interval: %d/%d", + minnum, mindenom); + gst_value_set_fraction (&min, minnum, mindenom); + + /* get the max */ + maxnum = ival.stepwise.max.numerator; + maxdenom = ival.stepwise.max.denominator; + if (maxnum > G_MAXINT || maxdenom > G_MAXINT) { + maxnum >>= 1; + maxdenom >>= 1; + } + + GST_LOG_OBJECT (v4l2object->element, "stepwise max frame interval: %d/%d", + maxnum, maxdenom); + gst_value_set_fraction (&max, maxnum, maxdenom); + + /* get the step */ + num = ival.stepwise.step.numerator; + denom = ival.stepwise.step.denominator; + if (num > G_MAXINT || denom > G_MAXINT) { + num >>= 1; + denom >>= 1; + } + + if (num == 0 || denom == 0) { + /* in this case we have a wrong fraction or no step, set the step to max + * so that we only add the min value in the loop below */ + num = maxnum; + denom = maxdenom; + } + + /* since we only have gst_value_fraction_subtract and not add, negate the + * numerator */ + GST_LOG_OBJECT (v4l2object->element, "stepwise step frame interval: %d/%d", + num, denom); + gst_value_set_fraction (&step, -num, denom); + + while (gst_value_compare (&min, &max) != GST_VALUE_GREATER_THAN) { + GValue rate = { 0, }; + + num = gst_value_get_fraction_numerator (&min); + denom = gst_value_get_fraction_denominator (&min); + GST_LOG_OBJECT (v4l2object->element, "adding stepwise framerate: %d/%d", + denom, num); + + /* invert to get the framerate */ + g_value_init (&rate, GST_TYPE_FRACTION); + gst_value_set_fraction (&rate, denom, num); + gst_value_list_append_value (&rates, &rate); + added = TRUE; + + /* we're actually adding because step was negated above. This is because + * there is no _add function... */ + if (!gst_value_fraction_subtract (&min, &min, &step)) { + GST_WARNING_OBJECT (v4l2object->element, "could not step fraction!"); + break; + } + } + if (!added) { + /* no range was added, leave the default range from the template */ + GST_WARNING_OBJECT (v4l2object->element, + "no range added, leaving default"); + g_value_unset (&rates); + } + } else if (ival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) { + guint32 maxnum, maxdenom; + + g_value_init (&rates, GST_TYPE_FRACTION_RANGE); + + num = ival.stepwise.min.numerator; + denom = ival.stepwise.min.denominator; + if (num > G_MAXINT || denom > G_MAXINT) { + num >>= 1; + denom >>= 1; + } + + maxnum = ival.stepwise.max.numerator; + maxdenom = ival.stepwise.max.denominator; + if (maxnum > G_MAXINT || maxdenom > G_MAXINT) { + maxnum >>= 1; + maxdenom >>= 1; + } + + GST_LOG_OBJECT (v4l2object->element, + "continuous frame interval %d/%d to %d/%d", maxdenom, maxnum, denom, + num); + + gst_value_set_fraction_range_full (&rates, maxdenom, maxnum, denom, num); + } else { + goto unknown_type; + } + +return_data: + s = gst_structure_copy (template); + gst_structure_set (s, "width", G_TYPE_INT, (gint) width, + "height", G_TYPE_INT, (gint) height, + "interlaced", G_TYPE_BOOLEAN, interlaced, + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL); + + if (G_IS_VALUE (&rates)) { + /* only change the framerate on the template when we have a valid probed new + * value */ + gst_structure_set_value (s, "framerate", &rates); + g_value_unset (&rates); + } else { + gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 100, 1, + NULL); + } + return s; + + /* ERRORS */ +enum_frameintervals_failed: + { + GST_DEBUG_OBJECT (v4l2object->element, + "Unable to enumerate intervals for %" GST_FOURCC_FORMAT "@%ux%u", + GST_FOURCC_ARGS (pixelformat), width, height); + goto return_data; + } +unknown_type: + { + /* I don't see how this is actually an error, we ignore the format then */ + GST_WARNING_OBJECT (v4l2object->element, + "Unknown frame interval type at %" GST_FOURCC_FORMAT "@%ux%u: %u", + GST_FOURCC_ARGS (pixelformat), width, height, ival.type); + return NULL; + } +} +#endif /* defined VIDIOC_ENUM_FRAMEINTERVALS */ + +#ifdef VIDIOC_ENUM_FRAMESIZES +static gint +sort_by_frame_size (GstStructure * s1, GstStructure * s2) +{ + int w1, h1, w2, h2; + + gst_structure_get_int (s1, "width", &w1); + gst_structure_get_int (s1, "height", &h1); + gst_structure_get_int (s2, "width", &w2); + gst_structure_get_int (s2, "height", &h2); + + /* I think it's safe to assume that this won't overflow for a while */ + return ((w2 * h2) - (w1 * h1)); +} +#endif + +GstCaps * +gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object, + guint32 pixelformat, const GstStructure * template) +{ + GstCaps *ret = gst_caps_new_empty (); + GstStructure *tmp; + +#ifdef VIDIOC_ENUM_FRAMESIZES + gint fd = v4l2object->video_fd; + struct v4l2_frmsizeenum size; + GList *results = NULL; + guint32 w, h; + + if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G')) + return gst_caps_new_simple ("video/mpegts", NULL); + + memset (&size, 0, sizeof (struct v4l2_frmsizeenum)); + size.index = 0; + size.pixel_format = pixelformat; + + GST_DEBUG_OBJECT (v4l2object->element, "Enumerating frame sizes"); + + if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0) + goto enum_framesizes_failed; + + if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { + do { + GST_LOG_OBJECT (v4l2object->element, "got discrete frame size %dx%d", + size.discrete.width, size.discrete.height); + + w = MIN (size.discrete.width, G_MAXINT); + h = MIN (size.discrete.height, G_MAXINT); + + if (w && h) { + tmp = + gst_v4l2_object_probe_caps_for_format_and_size (v4l2object, + pixelformat, w, h, template); + + if (tmp) + results = g_list_prepend (results, tmp); + } + + size.index++; + } while (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0); + GST_DEBUG_OBJECT (v4l2object->element, + "done iterating discrete frame sizes"); + } else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { + GST_DEBUG_OBJECT (v4l2object->element, "we have stepwise frame sizes:"); + GST_DEBUG_OBJECT (v4l2object->element, "min width: %d", + size.stepwise.min_width); + GST_DEBUG_OBJECT (v4l2object->element, "min height: %d", + size.stepwise.min_height); + GST_DEBUG_OBJECT (v4l2object->element, "max width: %d", + size.stepwise.max_width); + GST_DEBUG_OBJECT (v4l2object->element, "min height: %d", + size.stepwise.max_height); + GST_DEBUG_OBJECT (v4l2object->element, "step width: %d", + size.stepwise.step_width); + GST_DEBUG_OBJECT (v4l2object->element, "step height: %d", + size.stepwise.step_height); + + for (w = size.stepwise.min_width, h = size.stepwise.min_height; + w <= size.stepwise.max_width && h <= size.stepwise.max_height; + w += size.stepwise.step_width, h += size.stepwise.step_height) { + if (w == 0 || h == 0) + continue; + + tmp = + gst_v4l2_object_probe_caps_for_format_and_size (v4l2object, + pixelformat, w, h, template); + + if (tmp) + results = g_list_prepend (results, tmp); + } + GST_DEBUG_OBJECT (v4l2object->element, + "done iterating stepwise frame sizes"); + } else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { + guint32 maxw, maxh; + + GST_DEBUG_OBJECT (v4l2object->element, "we have continuous frame sizes:"); + GST_DEBUG_OBJECT (v4l2object->element, "min width: %d", + size.stepwise.min_width); + GST_DEBUG_OBJECT (v4l2object->element, "min height: %d", + size.stepwise.min_height); + GST_DEBUG_OBJECT (v4l2object->element, "max width: %d", + size.stepwise.max_width); + GST_DEBUG_OBJECT (v4l2object->element, "min height: %d", + size.stepwise.max_height); + + w = MAX (size.stepwise.min_width, 1); + h = MAX (size.stepwise.min_height, 1); + maxw = MIN (size.stepwise.max_width, G_MAXINT); + maxh = MIN (size.stepwise.max_height, G_MAXINT); + + tmp = + gst_v4l2_object_probe_caps_for_format_and_size (v4l2object, pixelformat, + w, h, template); + if (tmp) { + gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, (gint) w, + (gint) maxw, "height", GST_TYPE_INT_RANGE, (gint) h, (gint) maxh, + NULL); + + /* no point using the results list here, since there's only one struct */ + gst_caps_append_structure (ret, tmp); + } + } else { + goto unknown_type; + } + + /* we use an intermediary list to store and then sort the results of the + * probing because we can't make any assumptions about the order in which + * the driver will give us the sizes, but we want the final caps to contain + * the results starting with the highest resolution and having the lowest + * resolution last, since order in caps matters for things like fixation. */ + results = g_list_sort (results, (GCompareFunc) sort_by_frame_size); + while (results != NULL) { + gst_caps_append_structure (ret, GST_STRUCTURE (results->data)); + results = g_list_delete_link (results, results); + } + + if (gst_caps_is_empty (ret)) + goto enum_framesizes_no_results; + + return ret; + + /* ERRORS */ +enum_framesizes_failed: + { + /* I don't see how this is actually an error */ + GST_DEBUG_OBJECT (v4l2object->element, + "Failed to enumerate frame sizes for pixelformat %" GST_FOURCC_FORMAT + " (%s)", GST_FOURCC_ARGS (pixelformat), g_strerror (errno)); + goto default_frame_sizes; + } +enum_framesizes_no_results: + { + /* it's possible that VIDIOC_ENUM_FRAMESIZES is defined but the driver in + * question doesn't actually support it yet */ + GST_DEBUG_OBJECT (v4l2object->element, + "No results for pixelformat %" GST_FOURCC_FORMAT + " enumerating frame sizes, trying fallback", + GST_FOURCC_ARGS (pixelformat)); + goto default_frame_sizes; + } +unknown_type: + { + GST_WARNING_OBJECT (v4l2object->element, + "Unknown frame sizeenum type for pixelformat %" GST_FOURCC_FORMAT + ": %u", GST_FOURCC_ARGS (pixelformat), size.type); + goto default_frame_sizes; + } +default_frame_sizes: +#endif /* defined VIDIOC_ENUM_FRAMESIZES */ + { + gint min_w, max_w, min_h, max_h, fix_num = 0, fix_denom = 0; + gboolean interlaced; + + /* This code is for Linux < 2.6.19 */ + min_w = min_h = 1; + max_w = max_h = GST_V4L2_MAX_SIZE; + if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat, &min_w, + &min_h, &interlaced)) { + GST_WARNING_OBJECT (v4l2object->element, + "Could not probe minimum capture size for pixelformat %" + GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat)); + } + if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat, &max_w, + &max_h, &interlaced)) { + GST_WARNING_OBJECT (v4l2object->element, + "Could not probe maximum capture size for pixelformat %" + GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat)); + } + + /* Since we can't get framerate directly, try to use the current norm */ + if (v4l2object->tv_norm && v4l2object->norms) { + GList *norms; + GstTunerNorm *norm = NULL; + GstTunerNorm *current = + gst_v4l2_tuner_get_norm_by_std_id (v4l2object, v4l2object->tv_norm); + + for (norms = v4l2object->norms; norms != NULL; norms = norms->next) { + norm = (GstTunerNorm *) norms->data; + if (!strcmp (norm->label, current->label)) + break; + } + /* If it's possible, set framerate to that (discrete) value */ + if (norm) { + fix_num = gst_value_get_fraction_numerator (&norm->framerate); + fix_denom = gst_value_get_fraction_denominator (&norm->framerate); + } + } + + tmp = gst_structure_copy (template); + if (fix_num) { + gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION, fix_num, + fix_denom, NULL); + } else { + /* if norm can't be used, copy the template framerate */ + gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, + 100, 1, NULL); + } + + if (min_w == max_w) + gst_structure_set (tmp, "width", G_TYPE_INT, max_w, NULL); + else + gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, min_w, max_w, NULL); + + if (min_h == max_h) + gst_structure_set (tmp, "height", G_TYPE_INT, max_h, NULL); + else + gst_structure_set (tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL); + + gst_structure_set (tmp, "interlaced", G_TYPE_BOOLEAN, interlaced, NULL); + gst_structure_set (tmp, "pixel-aspect-ratio", + GST_TYPE_FRACTION, 1, 1, NULL); + + gst_caps_append_structure (ret, tmp); + + return ret; + } +} + +static gboolean +gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object, + guint32 pixelformat, gint * width, gint * height, gboolean * interlaced) +{ + struct v4l2_format fmt, prevfmt; + int fd; + int r; + int prevfmt_valid; + + g_return_val_if_fail (width != NULL, FALSE); + g_return_val_if_fail (height != NULL, FALSE); + + GST_LOG_OBJECT (v4l2object->element, + "getting nearest size to %dx%d with format %" GST_FOURCC_FORMAT, + *width, *height, GST_FOURCC_ARGS (pixelformat)); + + fd = v4l2object->video_fd; + + /* Some drivers are buggy and will modify the currently set format + when processing VIDIOC_TRY_FMT, so we remember what is set at the + minute, and will reset it when done. */ + prevfmt_valid = (v4l2_ioctl (fd, VIDIOC_G_FMT, &prevfmt) >= 0); + + /* get size delimiters */ + memset (&fmt, 0, sizeof (fmt)); + fmt.type = v4l2object->type; + fmt.fmt.pix.width = *width; + fmt.fmt.pix.height = *height; + fmt.fmt.pix.pixelformat = pixelformat; + fmt.fmt.pix.field = V4L2_FIELD_NONE; + + r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt); + if (r < 0 && errno == EINVAL) { + /* try again with interlaced video */ + fmt.fmt.pix.width = *width; + fmt.fmt.pix.height = *height; + fmt.fmt.pix.pixelformat = pixelformat; + fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; + r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt); + } + + if (r < 0) { + /* The driver might not implement TRY_FMT, in which case we will try + S_FMT to probe */ + if (errno != ENOTTY) + goto error; + + /* Only try S_FMT if we're not actively capturing yet, which we shouldn't + be, because we're still probing */ + if (GST_V4L2_IS_ACTIVE (v4l2object)) + goto error; + + GST_LOG_OBJECT (v4l2object->element, + "Failed to probe size limit with VIDIOC_TRY_FMT, trying VIDIOC_S_FMT"); + + fmt.fmt.pix.width = *width; + fmt.fmt.pix.height = *height; + + r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt); + if (r < 0 && errno == EINVAL) { + /* try again with progressive video */ + fmt.fmt.pix.width = *width; + fmt.fmt.pix.height = *height; + fmt.fmt.pix.pixelformat = pixelformat; + fmt.fmt.pix.field = V4L2_FIELD_NONE; + r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt); + } + + if (r < 0) + goto error; + } + + GST_LOG_OBJECT (v4l2object->element, + "got nearest size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height); + + *width = fmt.fmt.pix.width; + *height = fmt.fmt.pix.height; + + switch (fmt.fmt.pix.field) { + case V4L2_FIELD_ANY: + case V4L2_FIELD_NONE: + *interlaced = FALSE; + break; + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + *interlaced = TRUE; + break; + default: + GST_WARNING_OBJECT (v4l2object->element, + "Unsupported field type for %" GST_FOURCC_FORMAT "@%ux%u", + GST_FOURCC_ARGS (pixelformat), *width, *height); + goto error; + } + + if (prevfmt_valid) + v4l2_ioctl (fd, VIDIOC_S_FMT, &prevfmt); + return TRUE; + +error: + if (prevfmt_valid) + v4l2_ioctl (fd, VIDIOC_S_FMT, &prevfmt); + return FALSE; +} + + +gboolean +gst_v4l2_object_set_format (GstV4l2Object * v4l2object, guint32 pixelformat, + guint32 width, guint32 height, gboolean interlaced) +{ + gint fd = v4l2object->video_fd; + struct v4l2_format format; + enum v4l2_field field; + + if (interlaced) { + GST_DEBUG_OBJECT (v4l2object->element, "interlaced video"); + /* ideally we would differentiate between types of interlaced video + * but there is not sufficient information in the caps.. + */ + field = V4L2_FIELD_INTERLACED; + } else { + GST_DEBUG_OBJECT (v4l2object->element, "progressive video"); + field = V4L2_FIELD_NONE; + } + + GST_DEBUG_OBJECT (v4l2object->element, "Setting format to %dx%d, format " + "%" GST_FOURCC_FORMAT, width, height, GST_FOURCC_ARGS (pixelformat)); + + GST_V4L2_CHECK_OPEN (v4l2object); + GST_V4L2_CHECK_NOT_ACTIVE (v4l2object); + + /* Only unconditionally accept mpegts for sources */ + if ((v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))) + return TRUE; + + memset (&format, 0x00, sizeof (struct v4l2_format)); + format.type = v4l2object->type; + + if (v4l2_ioctl (fd, VIDIOC_G_FMT, &format) < 0) + goto get_fmt_failed; + + if (format.type == v4l2object->type && + format.fmt.pix.width == width && + format.fmt.pix.height == height && + format.fmt.pix.pixelformat == pixelformat && + format.fmt.pix.field == field) { + /* Nothing to do. We want to succeed immediately + * here because setting the same format back + * can still fail due to EBUSY. By short-circuiting + * here, we allow pausing and re-playing pipelines + * with changed caps, as long as the changed caps + * do not change the webcam's format. Otherwise, + * any caps change would require us to go to NULL + * state to close the device and set format. + */ + return TRUE; + } + + format.type = v4l2object->type; + format.fmt.pix.width = width; + format.fmt.pix.height = height; + format.fmt.pix.pixelformat = pixelformat; + format.fmt.pix.field = field; + + if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0) { + goto set_fmt_failed; + } + + if (format.fmt.pix.width != width || format.fmt.pix.height != height) + goto invalid_dimensions; + + if (format.fmt.pix.pixelformat != pixelformat) + goto invalid_pixelformat; + + return TRUE; + + /* ERRORS */ +get_fmt_failed: + { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, + (_("Device '%s' does not support video capture"), + v4l2object->videodev), + ("Call to G_FMT failed: (%s)", g_strerror (errno))); + return FALSE; + } +set_fmt_failed: + { + if (errno == EBUSY) { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, BUSY, + (_("Device '%s' is busy"), v4l2object->videodev), + ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s", + GST_FOURCC_ARGS (pixelformat), width, height, + g_strerror (errno))); + } else { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, + (_("Device '%s' cannot capture at %dx%d"), + v4l2object->videodev, width, height), + ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s", + GST_FOURCC_ARGS (pixelformat), width, height, + g_strerror (errno))); + } + return FALSE; + } +invalid_dimensions: + { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, + (_("Device '%s' cannot capture at %dx%d"), + v4l2object->videodev, width, height), + ("Tried to capture at %dx%d, but device returned size %dx%d", + width, height, format.fmt.pix.width, format.fmt.pix.height)); + return FALSE; + } +invalid_pixelformat: + { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, + (_("Device '%s' cannot capture in the specified format"), + v4l2object->videodev), + ("Tried to capture in %" GST_FOURCC_FORMAT + ", but device returned format" " %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (pixelformat), + GST_FOURCC_ARGS (format.fmt.pix.pixelformat))); + return FALSE; + } +} + +gboolean +gst_v4l2_object_start_streaming (GstV4l2Object * v4l2object) +{ + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_STREAMON, + &(v4l2object->type)) < 0) { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ, + (_("Error starting streaming on device '%s'."), v4l2object->videodev), + GST_ERROR_SYSTEM); + return FALSE; + } + return TRUE; +} + +gboolean +gst_v4l2_object_stop_streaming (GstV4l2Object * v4l2object) +{ + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_STREAMOFF, + &(v4l2object->type)) < 0) { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ, + (_("Error stopping streaming on device '%s'."), v4l2object->videodev), + GST_ERROR_SYSTEM); + return FALSE; + } + return TRUE; +} diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h new file mode 100644 index 0000000..a7b590d --- /dev/null +++ b/sys/v4l2/gstv4l2object.h @@ -0,0 +1,242 @@ +/* GStreamer + * + * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2object.h: base class for V4L2 elements + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_V4L2_OBJECT_H__ +#define __GST_V4L2_OBJECT_H__ + +/* Because of some really cool feature in video4linux1, also known as + * 'not including sys/types.h and sys/time.h', we had to include it + * ourselves. In all their intelligence, these people decided to fix + * this in the next version (video4linux2) in such a cool way that it + * breaks all compilations of old stuff... + * The real problem is actually that linux/time.h doesn't use proper + * macro checks before defining types like struct timeval. The proper + * fix here is to either fuck the kernel header (which is what we do + * by defining _LINUX_TIME_H, an innocent little hack) or by fixing it + * upstream, which I'll consider doing later on. If you get compiler + * errors here, check your linux/time.h && sys/time.h header setup. + */ +#include <sys/ioctl.h> +#include <sys/types.h> +#ifndef __sun +#include <linux/types.h> +#define _LINUX_TIME_H +#define __user +#include <linux/videodev2.h> +#else +#include <sys/videodev2.h> +#endif + +#include <gst/gst.h> +#include <gst/base/gstpushsrc.h> +#include <gst/controller/gstcontroller.h> + +#include <gst/interfaces/propertyprobe.h> + + +/* size of v4l2 buffer pool in streaming case */ +#define GST_V4L2_MAX_BUFFERS 16 +#define GST_V4L2_MIN_BUFFERS 1 + +/* max frame width/height */ +#define GST_V4L2_MAX_SIZE (1<<15) /* 2^15 == 32768 */ + + + +G_BEGIN_DECLS + +#define GST_V4L2_OBJECT(obj) (GstV4l2Object *)(obj) + +typedef struct _GstV4l2Object GstV4l2Object; +typedef struct _GstV4l2ObjectClassHelper GstV4l2ObjectClassHelper; +typedef struct _GstV4l2Xv GstV4l2Xv; + +typedef gboolean (*GstV4l2GetInOutFunction) (GstV4l2Object * v4l2object, gint * input); +typedef gboolean (*GstV4l2SetInOutFunction) (GstV4l2Object * v4l2object, gint input); +typedef gboolean (*GstV4l2UpdateFpsFunction) (GstV4l2Object * v4l2object); + +struct _GstV4l2Object { + GstElement * element; + + /* the video device */ + char *videodev; + + /* the video-device's file descriptor */ + gint video_fd; + GstPoll * poll; + gboolean can_poll_device; + + /* the video buffer (mmap()'ed) */ + guint8 **buffer; + + enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT */ + + /* the video device's capabilities */ + struct v4l2_capability vcap; + + /* the video device's window properties */ + struct v4l2_window vwin; + + /* some more info about the current input's capabilities */ + struct v4l2_input vinput; + + /* lists... */ + GSList *formats; /* list of available capture formats */ + + GList *colors; + GList *norms; + GList *channels; + + /* properties */ + v4l2_std_id tv_norm; + gchar *channel; + gulong frequency; + + /* X-overlay */ + GstV4l2Xv *xv; + gulong xwindow_id; + + /* funcs */ + GstV4l2GetInOutFunction get_in_out_func; + GstV4l2SetInOutFunction set_in_out_func; + GstV4l2UpdateFpsFunction update_fps_func; +}; + +struct _GstV4l2ObjectClassHelper { + /* probed devices */ + GList *devices; +}; + +GType gst_v4l2_object_get_type (void); + +#define V4L2_STD_OBJECT_PROPS \ + PROP_DEVICE, \ + PROP_DEVICE_NAME, \ + PROP_DEVICE_FD, \ + PROP_FLAGS, \ + PROP_BRIGHTNESS, \ + PROP_CONTRAST, \ + PROP_SATURATION, \ + PROP_HUE, \ + PROP_TV_NORM + +/* create/destroy */ +GstV4l2Object * gst_v4l2_object_new (GstElement * element, + enum v4l2_buf_type type, + const char *default_device, + GstV4l2GetInOutFunction get_in_out_func, + GstV4l2SetInOutFunction set_in_out_func, + GstV4l2UpdateFpsFunction update_fps_func); +void gst_v4l2_object_destroy (GstV4l2Object * v4l2object); + +/* properties */ + +void gst_v4l2_object_install_properties_helper (GObjectClass *gobject_class, const char *default_device); + +gboolean gst_v4l2_object_set_property_helper (GstV4l2Object *v4l2object, + guint prop_id, const GValue * value, + GParamSpec * pspec); +gboolean gst_v4l2_object_get_property_helper (GstV4l2Object *v4l2object, + guint prop_id, GValue * value, + GParamSpec * pspec); +/* starting/stopping */ +gboolean gst_v4l2_object_start (GstV4l2Object *v4l2object); +gboolean gst_v4l2_object_stop (GstV4l2Object *v4l2object); + +/* probing */ +const GList* gst_v4l2_probe_get_properties (GstPropertyProbe * probe); + +void gst_v4l2_probe_probe_property (GstPropertyProbe * probe, guint prop_id, + const GParamSpec * pspec, + GList ** klass_devices); +gboolean gst_v4l2_probe_needs_probe (GstPropertyProbe * probe, guint prop_id, + const GParamSpec * pspec, + GList ** klass_devices); +GValueArray* gst_v4l2_probe_get_values (GstPropertyProbe * probe, guint prop_id, + const GParamSpec * pspec, + GList ** klass_devices); + +GstCaps* gst_v4l2_object_probe_caps_for_format (GstV4l2Object *v4l2object, guint32 pixelformat, + const GstStructure * template); + +gboolean gst_v4l2_object_get_caps_info (GstV4l2Object *v4l2object, GstCaps *caps, + struct v4l2_fmtdesc **format, gint *w, gint *h, + gboolean * interlaced, guint *fps_n, guint *fps_d, guint *size); + + +GSList* gst_v4l2_object_get_format_list (GstV4l2Object *v4l2object); + +GstCaps* gst_v4l2_object_get_all_caps (void); + +GstStructure* gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc); + +gboolean gst_v4l2_object_set_format (GstV4l2Object *v4l2object, guint32 pixelformat, guint32 width, guint32 height, gboolean interlaced); + +gboolean gst_v4l2_object_start_streaming (GstV4l2Object *v4l2object); +gboolean gst_v4l2_object_stop_streaming (GstV4l2Object *v4l2object); + + +#define GST_IMPLEMENT_V4L2_PROBE_METHODS(Type_Class, interface_as_function) \ + \ +static void \ +interface_as_function ## _probe_probe_property (GstPropertyProbe * probe, \ + guint prop_id, \ + const GParamSpec * pspec) \ +{ \ + Type_Class *this_class = (Type_Class*) G_OBJECT_GET_CLASS (probe); \ + gst_v4l2_probe_probe_property (probe, prop_id, pspec, \ + &this_class->v4l2_class_devices); \ +} \ + \ +static gboolean \ +interface_as_function ## _probe_needs_probe (GstPropertyProbe * probe, \ + guint prop_id, \ + const GParamSpec * pspec) \ +{ \ + Type_Class *this_class = (Type_Class*) G_OBJECT_GET_CLASS (probe); \ + return gst_v4l2_probe_needs_probe (probe, prop_id, pspec, \ + &this_class->v4l2_class_devices); \ +} \ + \ +static GValueArray * \ +interface_as_function ## _probe_get_values (GstPropertyProbe * probe, \ + guint prop_id, \ + const GParamSpec * pspec) \ +{ \ + Type_Class *this_class = (Type_Class*) G_OBJECT_GET_CLASS (probe); \ + return gst_v4l2_probe_get_values (probe, prop_id, pspec, \ + &this_class->v4l2_class_devices); \ +} \ + \ +static void \ +interface_as_function ## _property_probe_interface_init (GstPropertyProbeInterface * iface) \ +{ \ + iface->get_properties = gst_v4l2_probe_get_properties; \ + iface->probe_property = interface_as_function ## _probe_probe_property; \ + iface->needs_probe = interface_as_function ## _probe_needs_probe; \ + iface->get_values = interface_as_function ## _probe_get_values; \ +} + +G_END_DECLS + +#endif /* __GST_V4L2_OBJECT_H__ */ diff --git a/sys/v4l2/gstv4l2radio.c b/sys/v4l2/gstv4l2radio.c new file mode 100644 index 0000000..63a2fed --- /dev/null +++ b/sys/v4l2/gstv4l2radio.c @@ -0,0 +1,635 @@ +/* GStreamer v4l2 radio tuner element + * Copyright (C) 2010, 2011 Alexey Chernov <4ernov@gmail.com> + * + * gstv4l2radio.c - V4L2 radio tuner element + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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-v4l2radio + * + * v4l2radio can be used to control radio device + * and to tune it to different radiostations. + * + * <refsect2> + * <title>Example launch lines</title> + * |[ + * gst-launch v4l2radio device=/dev/radio0 frequency=101200000 + * gst-launch alsasrc device=hw:1 ! audioconvert ! audioresample ! alsasink + * ]| + * First pipeline tunes the radio device /dev/radio0 to station 101.2 MHz, + * second pipeline connects digital audio out (hw:1) to default sound card. + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> + +#include "gst/gst-i18n-plugin.h" + +#include "gstv4l2tuner.h" +#include "gstv4l2radio.h" +#include "v4l2_calls.h" + +GST_DEBUG_CATEGORY_STATIC (v4l2radio_debug); +#define GST_CAT_DEFAULT v4l2radio_debug + +#define DEFAULT_PROP_DEVICE "/dev/radio0" +#define MIN_FREQUENCY 87500000 +#define DEFAULT_FREQUENCY 100000000 +#define MAX_FREQUENCY 108000000 + +enum +{ + ARG_0, + ARG_DEVICE, + ARG_FREQUENCY +}; + +static gboolean +gst_v4l2radio_fill_channel_list (GstV4l2Radio * radio) +{ + int res; + struct v4l2_tuner vtun; + struct v4l2_capability vc; + GstV4l2TunerChannel *v4l2channel; + GstTunerChannel *channel; + + GstElement *e; + + GstV4l2Object *v4l2object; + + e = GST_ELEMENT (radio); + v4l2object = radio->v4l2object; + + GST_DEBUG_OBJECT (e, "getting audio enumeration"); + GST_V4L2_CHECK_OPEN (v4l2object); + + GST_DEBUG_OBJECT (e, " audio input"); + + memset (&vc, 0, sizeof (vc)); + + res = v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &vc); + if (res < 0) + goto caps_failed; + + if (!(vc.capabilities & V4L2_CAP_TUNER)) + goto not_a_tuner; + + /* getting audio input */ + memset (&vtun, 0, sizeof (vtun)); + vtun.index = 0; + + res = v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun); + if (res < 0) + goto tuner_failed; + + GST_LOG_OBJECT (e, " index: %d", vtun.index); + GST_LOG_OBJECT (e, " name: '%s'", vtun.name); + GST_LOG_OBJECT (e, " type: %016x", (guint) vtun.type); + GST_LOG_OBJECT (e, " caps: %016x", (guint) vtun.capability); + GST_LOG_OBJECT (e, " rlow: %016x", (guint) vtun.rangelow); + GST_LOG_OBJECT (e, " rhigh: %016x", (guint) vtun.rangehigh); + GST_LOG_OBJECT (e, " audmode: %016x", (guint) vtun.audmode); + + v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL); + channel = GST_TUNER_CHANNEL (v4l2channel); + channel->label = g_strdup ((const gchar *) vtun.name); + channel->flags = GST_TUNER_CHANNEL_FREQUENCY | GST_TUNER_CHANNEL_AUDIO; + v4l2channel->index = 0; + v4l2channel->tuner = 0; + + channel->freq_multiplicator = + 62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW) ? 1 : 1000); + channel->min_frequency = vtun.rangelow * channel->freq_multiplicator; + channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator; + channel->min_signal = 0; + channel->max_signal = 0xffff; + + v4l2object->channels = + g_list_prepend (v4l2object->channels, (gpointer) channel); + + v4l2object->channels = g_list_reverse (v4l2object->channels); + + GST_DEBUG_OBJECT (e, "done"); + return TRUE; + + /* ERRORS */ +tuner_failed: + { + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, + (_("Failed to get settings of tuner %d on device '%s'."), + vtun.index, v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +caps_failed: + { + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, + (_("Error getting capabilities for device '%s'."), + v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +not_a_tuner: + { + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, + (_("Device '%s' is not a tuner."), + v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + +static gboolean +gst_v4l2radio_get_input (GstV4l2Object * v4l2object, gint * input) +{ + GST_DEBUG_OBJECT (v4l2object->element, "trying to get radio input"); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (!v4l2object->channels) + goto input_failed; + + *input = 0; + + GST_DEBUG_OBJECT (v4l2object->element, "input: %d", 0); + + return TRUE; + + /* ERRORS */ +input_failed: + { + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to get radio input on device '%s'. "), + v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + +static gboolean +gst_v4l2radio_set_input (GstV4l2Object * v4l2object, gint input) +{ + GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (!v4l2object->channels) + goto input_failed; + + return TRUE; + + /* ERRORS */ +input_failed: + { + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to set input %d on device %s."), + input, v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + +static gboolean +gst_v4l2radio_set_mute_on (GstV4l2Radio * radio, gboolean on) +{ + gint res; + struct v4l2_control vctrl; + + GST_DEBUG_OBJECT (radio, "setting current tuner mute state: %d", on); + + if (!GST_V4L2_IS_OPEN (radio->v4l2object)) + return FALSE; + + memset (&vctrl, 0, sizeof (vctrl)); + vctrl.id = V4L2_CID_AUDIO_MUTE; + vctrl.value = on; + + GST_DEBUG_OBJECT (radio, "radio fd: %d", radio->v4l2object->video_fd); + + res = ioctl (radio->v4l2object->video_fd, VIDIOC_S_CTRL, &vctrl); + GST_DEBUG_OBJECT (radio, "mute state change result: %d", res); + if (res < 0) + goto freq_failed; + + return TRUE; + + /* ERRORS */ +freq_failed: + { + GST_ELEMENT_WARNING (radio, RESOURCE, SETTINGS, + (_("Failed to change mute state for device '%s'."), + radio->v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + +static gboolean +gst_v4l2radio_set_mute (GstV4l2Radio * radio) +{ + return gst_v4l2radio_set_mute_on (radio, TRUE); +} + +static gboolean +gst_v4l2radio_set_unmute (GstV4l2Radio * radio) +{ + return gst_v4l2radio_set_mute_on (radio, FALSE); +} + +GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2RadioClass, gst_v4l2radio); +GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Radio, gst_v4l2radio); + +static void gst_v4l2radio_uri_handler_init (gpointer g_iface, + gpointer iface_data); + +static gboolean +gst_v4l2radio_interface_supported (GstImplementsInterface * iface, + GType iface_type) +{ + if (iface_type == GST_TYPE_TUNER) + return TRUE; + else + return FALSE; +} + +static void +gst_v4l2radio_implements_interface_init (GstImplementsInterfaceClass * iface) +{ + iface->supported = gst_v4l2radio_interface_supported; +} + +static void +gst_v4l2radio_tuner_interface_reinit (GstTunerClass * iface) +{ + gst_v4l2radio_tuner_interface_init (iface); +} + +static void +gst_v4l2radio_interfaces (GType type) +{ + static const GInterfaceInfo urihandler_info = { + (GInterfaceInitFunc) gst_v4l2radio_uri_handler_init, + NULL, + NULL + }; + + static const GInterfaceInfo implements_interface_info = { + (GInterfaceInitFunc) gst_v4l2radio_implements_interface_init, + NULL, + NULL, + }; + + static const GInterfaceInfo propertyprobe_info = { + (GInterfaceInitFunc) gst_v4l2radio_property_probe_interface_init, + NULL, + NULL, + }; + + static const GInterfaceInfo tuner_interface_info = { + (GInterfaceInitFunc) gst_v4l2radio_tuner_interface_reinit, + NULL, + NULL, + }; + + g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info); + g_type_add_interface_static (type, + GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info); + + g_type_add_interface_static (type, GST_TYPE_TUNER, &tuner_interface_info); + + g_type_add_interface_static (type, + GST_TYPE_PROPERTY_PROBE, &propertyprobe_info); +} + +GST_BOILERPLATE_FULL (GstV4l2Radio, gst_v4l2radio, GstElement, GST_TYPE_ELEMENT, + gst_v4l2radio_interfaces); + +static void gst_v4l2radio_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_v4l2radio_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_v4l2radio_finalize (GstV4l2Radio * radio); +static void gst_v4l2radio_dispose (GObject * object); +static GstStateChangeReturn gst_v4l2radio_change_state (GstElement * element, + GstStateChange transition); + +static void +gst_v4l2radio_base_init (gpointer gclass) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (gclass); + GstV4l2RadioClass *gstv4l2radio_class = GST_V4L2RADIO_CLASS (gclass); + + GST_DEBUG_CATEGORY_INIT (v4l2radio_debug, "v4l2radio", 0, + "V4l2 radio element"); + + gstv4l2radio_class->v4l2_class_devices = NULL; + + gst_element_class_set_details_simple (gstelement_class, + "Radio (video4linux2) Tuner", + "Tuner", + "Controls a Video4Linux2 radio device", + "Alexey Chernov <4ernov@gmail.com>"); +} + +static void +gst_v4l2radio_class_init (GstV4l2RadioClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + gobject_class->set_property = gst_v4l2radio_set_property; + gobject_class->get_property = gst_v4l2radio_get_property; + + g_object_class_install_property (gobject_class, ARG_DEVICE, + g_param_spec_string ("device", "Radio device location", + "Video4Linux2 radio device location", + DEFAULT_PROP_DEVICE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, ARG_FREQUENCY, + g_param_spec_int ("frequency", "Station frequency", + "Station frequency in Hz", + MIN_FREQUENCY, MAX_FREQUENCY, DEFAULT_FREQUENCY, G_PARAM_READWRITE)); + + gobject_class->dispose = gst_v4l2radio_dispose; + gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2radio_finalize; + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_v4l2radio_change_state); + +} + +static void +gst_v4l2radio_init (GstV4l2Radio * filter, GstV4l2RadioClass * gclass) +{ + filter->v4l2object = gst_v4l2_object_new (GST_ELEMENT (filter), + V4L2_BUF_TYPE_VIDEO_CAPTURE, DEFAULT_PROP_DEVICE, + gst_v4l2radio_get_input, gst_v4l2radio_set_input, NULL); + + filter->v4l2object->frequency = DEFAULT_FREQUENCY; + g_free (filter->v4l2object->videodev); + filter->v4l2object->videodev = g_strdup (DEFAULT_PROP_DEVICE); +} + +static void +gst_v4l2radio_dispose (GObject * object) +{ + GstV4l2Radio *radio = GST_V4L2RADIO (object); + gst_v4l2_close (radio->v4l2object); + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_v4l2radio_finalize (GstV4l2Radio * radio) +{ + gst_v4l2_object_destroy (radio->v4l2object); + G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (radio)); +} + +static gboolean +gst_v4l2radio_open (GstV4l2Radio * radio) +{ + GstV4l2Object *v4l2object; + + v4l2object = radio->v4l2object; + if (gst_v4l2_open (v4l2object)) + return gst_v4l2radio_fill_channel_list (radio); + else + return FALSE; +} + +static void +gst_v4l2radio_set_defaults (GstV4l2Radio * radio) +{ + GstV4l2Object *v4l2object; + GstTunerChannel *channel = NULL; + GstTuner *tuner; + + v4l2object = radio->v4l2object; + + if (!GST_IS_TUNER (v4l2object->element)) + return; + + tuner = GST_TUNER (v4l2object->element); + + if (v4l2object->channel) + channel = gst_tuner_find_channel_by_name (tuner, v4l2object->channel); + if (channel) { + gst_tuner_set_channel (tuner, channel); + } else { + channel = + GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER + (v4l2object->element))); + if (channel) { + g_free (v4l2object->channel); + v4l2object->channel = g_strdup (channel->label); + gst_tuner_channel_changed (tuner, channel); + } + } + + if (channel + && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { + if (v4l2object->frequency != 0) { + gst_tuner_set_frequency (tuner, channel, v4l2object->frequency); + } else { + v4l2object->frequency = gst_tuner_get_frequency (tuner, channel); + if (v4l2object->frequency == 0) { + /* guess */ + gst_tuner_set_frequency (tuner, channel, MIN_FREQUENCY); + } else { + } + } + } +} + +static gboolean +gst_v4l2radio_start (GstV4l2Radio * radio) +{ + if (!gst_v4l2radio_open (radio)) + return FALSE; + + gst_v4l2radio_set_defaults (radio); + + return TRUE; +} + +static gboolean +gst_v4l2radio_stop (GstV4l2Radio * radio) +{ + if (!gst_v4l2_object_stop (radio->v4l2object)) + return FALSE; + + return TRUE; +} + +static GstStateChangeReturn +gst_v4l2radio_change_state (GstElement * element, GstStateChange transition) +{ + GstV4l2Radio *radio; + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + radio = GST_V4L2RADIO (element); + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + /*start radio */ + if (!gst_v4l2radio_start (radio)) + ret = GST_STATE_CHANGE_FAILURE; + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + /*unmute radio */ + if (!gst_v4l2radio_set_unmute (radio)) + ret = GST_STATE_CHANGE_FAILURE; + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + /*mute radio */ + if (!gst_v4l2radio_set_mute (radio)) + ret = GST_STATE_CHANGE_FAILURE; + break; + case GST_STATE_CHANGE_READY_TO_NULL: + /*stop radio */ + if (!gst_v4l2radio_stop (radio)) + ret = GST_STATE_CHANGE_FAILURE; + break; + default: + break; + } + + return ret; +} + +static void +gst_v4l2radio_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstV4l2Radio *radio = GST_V4L2RADIO (object); + gint frequency; + switch (prop_id) { + case ARG_DEVICE: + g_free (radio->v4l2object->videodev); + radio->v4l2object->videodev = + g_strdup ((gchar *) g_value_get_string (value)); + break; + case ARG_FREQUENCY: + frequency = g_value_get_int (value); + if (frequency >= MIN_FREQUENCY && frequency <= MAX_FREQUENCY) { + radio->v4l2object->frequency = frequency; + gst_v4l2_set_frequency (radio->v4l2object, 0, + radio->v4l2object->frequency); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_v4l2radio_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstV4l2Radio *radio = GST_V4L2RADIO (object); + + switch (prop_id) { + case ARG_DEVICE: + g_value_set_string (value, radio->v4l2object->videodev); + break; + case ARG_FREQUENCY: + if (gst_v4l2_get_frequency (radio->v4l2object, + 0, &(radio->v4l2object->frequency))) + g_value_set_int (value, radio->v4l2object->frequency); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/* GstURIHandler interface */ +static GstURIType +gst_v4l2radio_uri_get_type (void) +{ + return GST_URI_SRC; +} + +static gchar ** +gst_v4l2radio_uri_get_protocols (void) +{ + static gchar *protocols[] = { (char *) "radio", NULL }; + return protocols; +} + +static const gchar * +gst_v4l2radio_uri_get_uri (GstURIHandler * handler) +{ + GstV4l2Radio *radio = GST_V4L2RADIO (handler); + + if (radio->v4l2object->videodev != NULL) { + if (gst_v4l2_get_frequency (radio->v4l2object, + 0, &(radio->v4l2object->frequency))) { + gchar uri[20]; + gchar freq[6]; + g_ascii_formatd (freq, 6, "%4.1f", radio->v4l2object->frequency / 1e6); + g_snprintf (uri, sizeof (uri), "radio://%s", freq); + return g_intern_string (uri); + } + } + + return "radio://"; +} + +static gboolean +gst_v4l2radio_uri_set_uri (GstURIHandler * handler, const gchar * uri) +{ + GstV4l2Radio *radio = GST_V4L2RADIO (handler); + gdouble dfreq; + gint ifreq; + const gchar *freq; + gchar *end; + + if (strcmp (uri, "radio://") != 0) { + freq = uri + 8; + + dfreq = g_ascii_strtod (freq, &end); + + if (errno || strlen (end)) + goto uri_failed; + + ifreq = dfreq * 1e6; + g_object_set (radio, "frequency", ifreq, NULL); + + } else + goto uri_failed; + + return TRUE; + +uri_failed: + return FALSE; +} + +static void +gst_v4l2radio_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_v4l2radio_uri_get_type; + iface->get_protocols = gst_v4l2radio_uri_get_protocols; + iface->get_uri = gst_v4l2radio_uri_get_uri; + iface->set_uri = gst_v4l2radio_uri_set_uri; +} diff --git a/sys/v4l2/gstv4l2radio.h b/sys/v4l2/gstv4l2radio.h new file mode 100644 index 0000000..68b7ec3 --- /dev/null +++ b/sys/v4l2/gstv4l2radio.h @@ -0,0 +1,67 @@ +/* GStreamer v4l2 radio tuner element + * Copyright (C) 2010, 2011 Alexey Chernov <4ernov@gmail.com> + * + * gstv4l2radio.h - V4L2 radio tuner element + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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_V4L2RADIO_H__ +#define __GST_V4L2RADIO_H__ + +#include "gstv4l2object.h" + +G_BEGIN_DECLS + +#define GST_TYPE_V4L2RADIO \ + (gst_v4l2radio_get_type()) +#define GST_V4L2RADIO(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2RADIO,GstV4l2Radio)) +#define GST_V4L2RADIO_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2RADIO,GstV4l2RadioClass)) +#define GST_IS_V4L2RADIO(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2RADIO)) +#define GST_IS_V4L2RADIO_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2RADIO)) + +typedef struct _GstV4l2Radio GstV4l2Radio; +typedef struct _GstV4l2RadioClass GstV4l2RadioClass; + +/** + * GstV4l2Radio: + * + * Opaque video4linux2 radio tuner element + */ +struct _GstV4l2Radio +{ + GstElement element; + + /*< private >*/ + GstV4l2Object * v4l2object; +}; + +struct _GstV4l2RadioClass +{ + GstElementClass parent_class; + + GList *v4l2_class_devices; +}; + +GType gst_v4l2radio_get_type (void); + +G_END_DECLS + +#endif /* __GST_V4L2RADIO_H__ */ diff --git a/sys/v4l2/gstv4l2sink.c b/sys/v4l2/gstv4l2sink.c new file mode 100644 index 0000000..f6aba24 --- /dev/null +++ b/sys/v4l2/gstv4l2sink.c @@ -0,0 +1,971 @@ +/* GStreamer + * + * Copyright (C) 2009 Texas Instruments, Inc - http://www.ti.com/ + * + * Description: V4L2 sink element + * Created on: Jul 2, 2009 + * Author: Rob Clark <rob@ti.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-v4l2sink + * + * v4l2sink can be used to display video to v4l2 devices (screen overlays + * provided by the graphics hardware, tv-out, etc) + * + * <refsect2> + * <title>Example launch lines</title> + * |[ + * gst-launch videotestsrc ! v4l2sink device=/dev/video1 + * ]| This pipeline displays a test pattern on /dev/video1 + * |[ + * gst-launch -v videotestsrc ! navigationtest ! v4l2sink + * ]| A pipeline to test navigation events. + * While moving the mouse pointer over the test signal you will see a black box + * following the mouse pointer. If you press the mouse button somewhere on the + * video and release it somewhere else a green box will appear where you pressed + * the button and a red one where you released it. (The navigationtest element + * is part of gst-plugins-good.) You can observe here that even if the images + * are scaled through hardware the pointer coordinates are converted back to the + * original video frame geometry so that the box can be drawn to the correct + * position. This also handles borders correctly, limiting coordinates to the + * image area + * </refsect2> + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include "gstv4l2colorbalance.h" +#include "gstv4l2tuner.h" +#ifdef HAVE_XVIDEO +#include "gstv4l2xoverlay.h" +#endif +#include "gstv4l2vidorient.h" + +#include "gstv4l2sink.h" +#include "gst/gst-i18n-plugin.h" + +#include <string.h> + +GST_DEBUG_CATEGORY (v4l2sink_debug); +#define GST_CAT_DEFAULT v4l2sink_debug + +#define PROP_DEF_QUEUE_SIZE 12 +#define PROP_DEF_MIN_QUEUED_BUFS 1 +#define DEFAULT_PROP_DEVICE "/dev/video1" + +enum +{ + PROP_0, + V4L2_STD_OBJECT_PROPS, + PROP_QUEUE_SIZE, + PROP_MIN_QUEUED_BUFS, + PROP_OVERLAY_TOP, + PROP_OVERLAY_LEFT, + PROP_OVERLAY_WIDTH, + PROP_OVERLAY_HEIGHT, + PROP_CROP_TOP, + PROP_CROP_LEFT, + PROP_CROP_WIDTH, + PROP_CROP_HEIGHT, +}; + + +GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SinkClass, gst_v4l2sink); +GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS (GstV4l2Sink, gst_v4l2sink); +GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Sink, gst_v4l2sink); +#ifdef HAVE_XVIDEO +GST_IMPLEMENT_V4L2_XOVERLAY_METHODS (GstV4l2Sink, gst_v4l2sink); +#endif +GST_IMPLEMENT_V4L2_VIDORIENT_METHODS (GstV4l2Sink, gst_v4l2sink); + +static gboolean +gst_v4l2sink_iface_supported (GstImplementsInterface * iface, GType iface_type) +{ + GstV4l2Object *v4l2object = GST_V4L2SINK (iface)->v4l2object; + +#ifdef HAVE_XVIDEO + g_assert (iface_type == GST_TYPE_X_OVERLAY || + iface_type == GST_TYPE_NAVIGATION || + iface_type == GST_TYPE_COLOR_BALANCE || + iface_type == GST_TYPE_VIDEO_ORIENTATION || + iface_type == GST_TYPE_TUNER); +#else + g_assert (iface_type == GST_TYPE_COLOR_BALANCE || + iface_type == GST_TYPE_VIDEO_ORIENTATION || + iface_type == GST_TYPE_TUNER); +#endif + + if (v4l2object->video_fd == -1) + return FALSE; + +#ifdef HAVE_XVIDEO + if (!GST_V4L2_IS_OVERLAY (v4l2object)) { + if (iface_type == GST_TYPE_X_OVERLAY || iface_type == GST_TYPE_NAVIGATION) + return FALSE; + } +#endif + + return TRUE; +} + +static void +gst_v4l2sink_interface_init (GstImplementsInterfaceClass * klass) +{ + /* + * default virtual functions + */ + klass->supported = gst_v4l2sink_iface_supported; +} + +#ifdef HAVE_XVIDEO +static void gst_v4l2sink_navigation_send_event (GstNavigation * navigation, + GstStructure * structure); +static void +gst_v4l2sink_navigation_init (GstNavigationInterface * iface) +{ + iface->send_event = gst_v4l2sink_navigation_send_event; +} +#endif + +static void +gst_v4l2sink_init_interfaces (GType type) +{ + static const GInterfaceInfo v4l2iface_info = { + (GInterfaceInitFunc) gst_v4l2sink_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo v4l2_tuner_info = { + (GInterfaceInitFunc) gst_v4l2sink_tuner_interface_init, + NULL, + NULL, + }; +#ifdef HAVE_XVIDEO + static const GInterfaceInfo v4l2_xoverlay_info = { + (GInterfaceInitFunc) gst_v4l2sink_xoverlay_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo v4l2_navigation_info = { + (GInterfaceInitFunc) gst_v4l2sink_navigation_init, + NULL, + NULL, + }; +#endif + static const GInterfaceInfo v4l2_colorbalance_info = { + (GInterfaceInitFunc) gst_v4l2sink_color_balance_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo v4l2_videoorientation_info = { + (GInterfaceInitFunc) gst_v4l2sink_video_orientation_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo v4l2_propertyprobe_info = { + (GInterfaceInitFunc) gst_v4l2sink_property_probe_interface_init, + NULL, + NULL, + }; + + g_type_add_interface_static (type, + GST_TYPE_IMPLEMENTS_INTERFACE, &v4l2iface_info); + g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l2_tuner_info); +#ifdef HAVE_XVIDEO + g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l2_xoverlay_info); + g_type_add_interface_static (type, + GST_TYPE_NAVIGATION, &v4l2_navigation_info); +#endif + g_type_add_interface_static (type, + GST_TYPE_COLOR_BALANCE, &v4l2_colorbalance_info); + g_type_add_interface_static (type, + GST_TYPE_VIDEO_ORIENTATION, &v4l2_videoorientation_info); + g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE, + &v4l2_propertyprobe_info); +} + + +GST_BOILERPLATE_FULL (GstV4l2Sink, gst_v4l2sink, GstVideoSink, + GST_TYPE_VIDEO_SINK, gst_v4l2sink_init_interfaces); + + +static void gst_v4l2sink_dispose (GObject * object); +static void gst_v4l2sink_finalize (GstV4l2Sink * v4l2sink); + +/* GObject methods: */ +static void gst_v4l2sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_v4l2sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + + +/* GstElement methods: */ +static GstStateChangeReturn gst_v4l2sink_change_state (GstElement * element, + GstStateChange transition); + +/* GstBaseSink methods: */ +static GstCaps *gst_v4l2sink_get_caps (GstBaseSink * bsink); +static gboolean gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps); +static GstFlowReturn gst_v4l2sink_buffer_alloc (GstBaseSink * bsink, + guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); +static GstFlowReturn gst_v4l2sink_show_frame (GstBaseSink * bsink, + GstBuffer * buf); + +static void +gst_v4l2sink_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + GstV4l2SinkClass *gstv4l2sink_class = GST_V4L2SINK_CLASS (g_class); + GstPadTemplate *pad_template; + + gstv4l2sink_class->v4l2_class_devices = NULL; + + GST_DEBUG_CATEGORY_INIT (v4l2sink_debug, "v4l2sink", 0, "V4L2 sink element"); + + gst_element_class_set_details_simple (gstelement_class, + "Video (video4linux2) Sink", "Sink/Video", + "Displays frames on a video4linux2 device", "Rob Clark <rob@ti.com>,"); + + pad_template = + gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, + gst_v4l2_object_get_all_caps ()); + gst_element_class_add_pad_template (gstelement_class, pad_template); + gst_object_unref (pad_template); +} + +static void +gst_v4l2sink_class_init (GstV4l2SinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *element_class; + GstBaseSinkClass *basesink_class; + + gobject_class = G_OBJECT_CLASS (klass); + element_class = GST_ELEMENT_CLASS (klass); + basesink_class = GST_BASE_SINK_CLASS (klass); + + gobject_class->dispose = gst_v4l2sink_dispose; + gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2sink_finalize; + gobject_class->set_property = gst_v4l2sink_set_property; + gobject_class->get_property = gst_v4l2sink_get_property; + + element_class->change_state = gst_v4l2sink_change_state; + + gst_v4l2_object_install_properties_helper (gobject_class, + DEFAULT_PROP_DEVICE); + g_object_class_install_property (gobject_class, PROP_QUEUE_SIZE, + g_param_spec_uint ("queue-size", "Queue size", + "Number of buffers to be enqueud in the driver in streaming mode", + GST_V4L2_MIN_BUFFERS, GST_V4L2_MAX_BUFFERS, PROP_DEF_QUEUE_SIZE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MIN_QUEUED_BUFS, + g_param_spec_uint ("min-queued-bufs", "Minimum queued bufs", + "Minimum number of queued bufs; v4l2sink won't dqbuf if the driver " + "doesn't have more than this number (which normally you shouldn't change)", + 0, GST_V4L2_MAX_BUFFERS, PROP_DEF_MIN_QUEUED_BUFS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OVERLAY_TOP, + g_param_spec_int ("overlay-top", "Overlay top", + "The topmost (y) coordinate of the video overlay; top left corner of screen is 0,0", + G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OVERLAY_LEFT, + g_param_spec_int ("overlay-left", "Overlay left", + "The leftmost (x) coordinate of the video overlay; top left corner of screen is 0,0", + G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OVERLAY_WIDTH, + g_param_spec_uint ("overlay-width", "Overlay width", + "The width of the video overlay; default is equal to negotiated image width", + 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OVERLAY_HEIGHT, + g_param_spec_uint ("overlay-height", "Overlay height", + "The height of the video overlay; default is equal to negotiated image height", + 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_CROP_TOP, + g_param_spec_int ("crop-top", "Crop top", + "The topmost (y) coordinate of the video crop; top left corner of image is 0,0", + 0x80000000, 0x7fffffff, 0, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_CROP_LEFT, + g_param_spec_int ("crop-left", "Crop left", + "The leftmost (x) coordinate of the video crop; top left corner of image is 0,0", + 0x80000000, 0x7fffffff, 0, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_CROP_WIDTH, + g_param_spec_uint ("crop-width", "Crop width", + "The width of the video crop; default is equal to negotiated image width", + 0, 0xffffffff, 0, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_CROP_HEIGHT, + g_param_spec_uint ("crop-height", "Crop height", + "The height of the video crop; default is equal to negotiated image height", + 0, 0xffffffff, 0, G_PARAM_READWRITE)); + + basesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_v4l2sink_get_caps); + basesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_v4l2sink_set_caps); + basesink_class->buffer_alloc = GST_DEBUG_FUNCPTR (gst_v4l2sink_buffer_alloc); + basesink_class->render = GST_DEBUG_FUNCPTR (gst_v4l2sink_show_frame); +} + +static void +gst_v4l2sink_init (GstV4l2Sink * v4l2sink, GstV4l2SinkClass * klass) +{ + v4l2sink->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2sink), + V4L2_BUF_TYPE_VIDEO_OUTPUT, DEFAULT_PROP_DEVICE, + gst_v4l2_get_output, gst_v4l2_set_output, NULL); + + /* same default value for video output device as is used for + * v4l2src/capture is no good.. so lets set a saner default + * (which can be overridden by the one creating the v4l2sink + * after the constructor returns) + */ + g_object_set (v4l2sink, "device", "/dev/video1", NULL); + + /* number of buffers requested */ + v4l2sink->num_buffers = PROP_DEF_QUEUE_SIZE; + v4l2sink->min_queued_bufs = PROP_DEF_MIN_QUEUED_BUFS; + + v4l2sink->probed_caps = NULL; + v4l2sink->current_caps = NULL; + + v4l2sink->overlay_fields_set = 0; + v4l2sink->crop_fields_set = 0; + v4l2sink->state = 0; +} + + +static void +gst_v4l2sink_dispose (GObject * object) +{ + GstV4l2Sink *v4l2sink = GST_V4L2SINK (object); + + if (v4l2sink->probed_caps) { + gst_caps_unref (v4l2sink->probed_caps); + } + + if (v4l2sink->current_caps) { + gst_caps_unref (v4l2sink->current_caps); + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + + +static void +gst_v4l2sink_finalize (GstV4l2Sink * v4l2sink) +{ + gst_v4l2_object_destroy (v4l2sink->v4l2object); + + G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (v4l2sink)); +} + + +/* + * State values + */ +enum +{ + STATE_OFF = 0, + STATE_PENDING_STREAMON, + STATE_STREAMING +}; + +/* + * flags to indicate which overlay/crop properties the user has set (and + * therefore which ones should override the defaults from the driver) + */ +enum +{ + RECT_TOP_SET = 0x01, + RECT_LEFT_SET = 0x02, + RECT_WIDTH_SET = 0x04, + RECT_HEIGHT_SET = 0x08 +}; + +static void +gst_v4l2sink_sync_overlay_fields (GstV4l2Sink * v4l2sink) +{ + if (!v4l2sink->overlay_fields_set) + return; + + if (GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) { + + gint fd = v4l2sink->v4l2object->video_fd; + struct v4l2_format format; + + memset (&format, 0x00, sizeof (struct v4l2_format)); + format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + + if (v4l2_ioctl (fd, VIDIOC_G_FMT, &format) < 0) { + GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_FMT failed"); + return; + } + + GST_DEBUG_OBJECT (v4l2sink, + "setting overlay: overlay_fields_set=0x%02x, top=%d, left=%d, width=%d, height=%d", + v4l2sink->overlay_fields_set, + v4l2sink->overlay.top, v4l2sink->overlay.left, + v4l2sink->overlay.width, v4l2sink->overlay.height); + + if (v4l2sink->overlay_fields_set & RECT_TOP_SET) + format.fmt.win.w.top = v4l2sink->overlay.top; + if (v4l2sink->overlay_fields_set & RECT_LEFT_SET) + format.fmt.win.w.left = v4l2sink->overlay.left; + if (v4l2sink->overlay_fields_set & RECT_WIDTH_SET) + format.fmt.win.w.width = v4l2sink->overlay.width; + if (v4l2sink->overlay_fields_set & RECT_HEIGHT_SET) + format.fmt.win.w.height = v4l2sink->overlay.height; + + if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0) { + GST_WARNING_OBJECT (v4l2sink, "VIDIOC_S_FMT failed"); + return; + } + + v4l2sink->overlay_fields_set = 0; + v4l2sink->overlay = format.fmt.win.w; + } +} + +static void +gst_v4l2sink_sync_crop_fields (GstV4l2Sink * v4l2sink) +{ + if (!v4l2sink->crop_fields_set) + return; + + if (GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) { + + gint fd = v4l2sink->v4l2object->video_fd; + struct v4l2_crop crop; + + memset (&crop, 0x00, sizeof (struct v4l2_crop)); + crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + if (v4l2_ioctl (fd, VIDIOC_G_CROP, &crop) < 0) { + GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_CROP failed"); + return; + } + + GST_DEBUG_OBJECT (v4l2sink, + "setting crop: crop_fields_set=0x%02x, top=%d, left=%d, width=%d, height=%d", + v4l2sink->crop_fields_set, + v4l2sink->crop.top, v4l2sink->crop.left, + v4l2sink->crop.width, v4l2sink->crop.height); + + if (v4l2sink->crop_fields_set & RECT_TOP_SET) + crop.c.top = v4l2sink->crop.top; + if (v4l2sink->crop_fields_set & RECT_LEFT_SET) + crop.c.left = v4l2sink->crop.left; + if (v4l2sink->crop_fields_set & RECT_WIDTH_SET) + crop.c.width = v4l2sink->crop.width; + if (v4l2sink->crop_fields_set & RECT_HEIGHT_SET) + crop.c.height = v4l2sink->crop.height; + + if (v4l2_ioctl (fd, VIDIOC_S_CROP, &crop) < 0) { + GST_WARNING_OBJECT (v4l2sink, "VIDIOC_S_CROP failed"); + return; + } + + v4l2sink->crop_fields_set = 0; + v4l2sink->crop = crop.c; + } +} + + +static void +gst_v4l2sink_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstV4l2Sink *v4l2sink = GST_V4L2SINK (object); + + if (!gst_v4l2_object_set_property_helper (v4l2sink->v4l2object, + prop_id, value, pspec)) { + switch (prop_id) { + case PROP_QUEUE_SIZE: + v4l2sink->num_buffers = g_value_get_uint (value); + break; + case PROP_MIN_QUEUED_BUFS: + v4l2sink->min_queued_bufs = g_value_get_uint (value); + break; + case PROP_OVERLAY_TOP: + v4l2sink->overlay.top = g_value_get_int (value); + v4l2sink->overlay_fields_set |= RECT_TOP_SET; + gst_v4l2sink_sync_overlay_fields (v4l2sink); + break; + case PROP_OVERLAY_LEFT: + v4l2sink->overlay.left = g_value_get_int (value); + v4l2sink->overlay_fields_set |= RECT_LEFT_SET; + gst_v4l2sink_sync_overlay_fields (v4l2sink); + break; + case PROP_OVERLAY_WIDTH: + v4l2sink->overlay.width = g_value_get_uint (value); + v4l2sink->overlay_fields_set |= RECT_WIDTH_SET; + gst_v4l2sink_sync_overlay_fields (v4l2sink); + break; + case PROP_OVERLAY_HEIGHT: + v4l2sink->overlay.height = g_value_get_uint (value); + v4l2sink->overlay_fields_set |= RECT_HEIGHT_SET; + gst_v4l2sink_sync_overlay_fields (v4l2sink); + break; + case PROP_CROP_TOP: + v4l2sink->crop.top = g_value_get_int (value); + v4l2sink->crop_fields_set |= RECT_TOP_SET; + gst_v4l2sink_sync_crop_fields (v4l2sink); + break; + case PROP_CROP_LEFT: + v4l2sink->crop.left = g_value_get_int (value); + v4l2sink->crop_fields_set |= RECT_LEFT_SET; + gst_v4l2sink_sync_crop_fields (v4l2sink); + break; + case PROP_CROP_WIDTH: + v4l2sink->crop.width = g_value_get_uint (value); + v4l2sink->crop_fields_set |= RECT_WIDTH_SET; + gst_v4l2sink_sync_crop_fields (v4l2sink); + break; + case PROP_CROP_HEIGHT: + v4l2sink->crop.height = g_value_get_uint (value); + v4l2sink->crop_fields_set |= RECT_HEIGHT_SET; + gst_v4l2sink_sync_crop_fields (v4l2sink); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } +} + + +static void +gst_v4l2sink_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstV4l2Sink *v4l2sink = GST_V4L2SINK (object); + + if (!gst_v4l2_object_get_property_helper (v4l2sink->v4l2object, + prop_id, value, pspec)) { + switch (prop_id) { + case PROP_QUEUE_SIZE: + g_value_set_uint (value, v4l2sink->num_buffers); + break; + case PROP_MIN_QUEUED_BUFS: + g_value_set_uint (value, v4l2sink->min_queued_bufs); + break; + case PROP_OVERLAY_TOP: + g_value_set_int (value, v4l2sink->overlay.top); + break; + case PROP_OVERLAY_LEFT: + g_value_set_int (value, v4l2sink->overlay.left); + break; + case PROP_OVERLAY_WIDTH: + g_value_set_uint (value, v4l2sink->overlay.width); + break; + case PROP_OVERLAY_HEIGHT: + g_value_set_uint (value, v4l2sink->overlay.height); + break; + case PROP_CROP_TOP: + g_value_set_int (value, v4l2sink->crop.top); + break; + case PROP_CROP_LEFT: + g_value_set_int (value, v4l2sink->crop.left); + break; + case PROP_CROP_WIDTH: + g_value_set_uint (value, v4l2sink->crop.width); + break; + case PROP_CROP_HEIGHT: + g_value_set_uint (value, v4l2sink->crop.height); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } +} + +static GstStateChangeReturn +gst_v4l2sink_change_state (GstElement * element, GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstV4l2Sink *v4l2sink = GST_V4L2SINK (element); + + GST_DEBUG_OBJECT (v4l2sink, "%d -> %d", + GST_STATE_TRANSITION_CURRENT (transition), + GST_STATE_TRANSITION_NEXT (transition)); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + /* open the device */ + if (!gst_v4l2_object_start (v4l2sink->v4l2object)) + 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: + if (v4l2sink->state == STATE_STREAMING) { + if (!gst_v4l2_object_stop_streaming (v4l2sink->v4l2object)) { + return GST_STATE_CHANGE_FAILURE; + } + v4l2sink->state = STATE_PENDING_STREAMON; + } + break; + case GST_STATE_CHANGE_READY_TO_NULL: + if (NULL != v4l2sink->pool) + gst_v4l2_buffer_pool_destroy (v4l2sink->pool); + v4l2sink->pool = NULL; + /* close the device */ + if (!gst_v4l2_object_stop (v4l2sink->v4l2object)) + return GST_STATE_CHANGE_FAILURE; + v4l2sink->state = STATE_OFF; + break; + default: + break; + } + + return ret; +} + + +static GstCaps * +gst_v4l2sink_get_caps (GstBaseSink * bsink) +{ + GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink); + GstCaps *ret; + GSList *walk; + GSList *formats; + + if (!GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) { + /* FIXME: copy? */ + GST_DEBUG_OBJECT (v4l2sink, "device is not open"); + return + gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD + (v4l2sink))); + } + + if (v4l2sink->probed_caps) { + LOG_CAPS (v4l2sink, v4l2sink->probed_caps); + return gst_caps_ref (v4l2sink->probed_caps); + } + + formats = gst_v4l2_object_get_format_list (v4l2sink->v4l2object); + + ret = gst_caps_new_empty (); + + for (walk = formats; walk; walk = walk->next) { + struct v4l2_fmtdesc *format; + + GstStructure *template; + + format = (struct v4l2_fmtdesc *) walk->data; + + template = gst_v4l2_object_v4l2fourcc_to_structure (format->pixelformat); + + if (template) { + GstCaps *tmp; + + tmp = + gst_v4l2_object_probe_caps_for_format (v4l2sink->v4l2object, + format->pixelformat, template); + if (tmp) + gst_caps_append (ret, tmp); + + gst_structure_free (template); + } else { + GST_DEBUG_OBJECT (v4l2sink, "unknown format %u", format->pixelformat); + } + } + + v4l2sink->probed_caps = gst_caps_ref (ret); + + GST_INFO_OBJECT (v4l2sink, "probed caps: %p", ret); + LOG_CAPS (v4l2sink, ret); + + return ret; +} + +static gboolean +gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps) +{ + GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink); + gint w = 0, h = 0; + gboolean interlaced; + struct v4l2_fmtdesc *format; + guint fps_n, fps_d; + guint size; + + LOG_CAPS (v4l2sink, caps); + + if (!GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) { + GST_DEBUG_OBJECT (v4l2sink, "device is not open"); + return FALSE; + } + + if (v4l2sink->current_caps) { + GST_DEBUG_OBJECT (v4l2sink, "already have caps set.. are they equal?"); + LOG_CAPS (v4l2sink, v4l2sink->current_caps); + if (gst_caps_is_equal (v4l2sink->current_caps, caps)) { + GST_DEBUG_OBJECT (v4l2sink, "yes they are!"); + return TRUE; + } + GST_DEBUG_OBJECT (v4l2sink, "no they aren't!"); + } + + if (v4l2sink->pool) { + /* TODO: if we've already allocated buffers, we probably need to + * do something here to free and reallocate.... + * + * gst_v4l2_object_stop_streaming() + * gst_v4l2_buffer_pool_destroy() + * + */ + GST_DEBUG_OBJECT (v4l2sink, "warning, changing caps not supported yet"); + return FALSE; + } + + /* we want our own v4l2 type of fourcc codes */ + if (!gst_v4l2_object_get_caps_info (v4l2sink->v4l2object, caps, + &format, &w, &h, &interlaced, &fps_n, &fps_d, &size)) { + GST_DEBUG_OBJECT (v4l2sink, "can't get capture format from caps %p", caps); + return FALSE; + } + + if (!format) { + GST_DEBUG_OBJECT (v4l2sink, "unrecognized caps!!"); + return FALSE; + } + + if (!gst_v4l2_object_set_format (v4l2sink->v4l2object, format->pixelformat, + w, h, interlaced)) { + /* error already posted */ + return FALSE; + } + + v4l2sink->video_width = w; + v4l2sink->video_height = h; + + /* TODO: videosink width/height should be scaled according to + * pixel-aspect-ratio + */ + GST_VIDEO_SINK_WIDTH (v4l2sink) = w; + GST_VIDEO_SINK_HEIGHT (v4l2sink) = h; + + v4l2sink->current_caps = gst_caps_ref (caps); + + return TRUE; +} + +/* buffer alloc function to implement pad_alloc for upstream element */ +static GstFlowReturn +gst_v4l2sink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, + GstCaps * caps, GstBuffer ** buf) +{ + GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink); + GstV4l2Buffer *v4l2buf; + + if (v4l2sink->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) { + + /* initialize the buffer pool if not initialized yet (first buffer): */ + if (G_UNLIKELY (!v4l2sink->pool)) { + + /* set_caps() might not be called yet.. so just to make sure: */ + if (!gst_v4l2sink_set_caps (bsink, caps)) { + return GST_FLOW_ERROR; + } + + GST_V4L2_CHECK_OPEN (v4l2sink->v4l2object); + + if (!(v4l2sink->pool = gst_v4l2_buffer_pool_new (GST_ELEMENT (v4l2sink), + v4l2sink->v4l2object->video_fd, + v4l2sink->num_buffers, caps, FALSE, + V4L2_BUF_TYPE_VIDEO_OUTPUT))) { + return GST_FLOW_ERROR; + } + + gst_v4l2sink_sync_overlay_fields (v4l2sink); + gst_v4l2sink_sync_crop_fields (v4l2sink); + +#ifdef HAVE_XVIDEO + gst_v4l2_xoverlay_prepare_xwindow_id (v4l2sink->v4l2object, TRUE); +#endif + + v4l2sink->state = STATE_PENDING_STREAMON; + + GST_INFO_OBJECT (v4l2sink, "outputting buffers via mmap()"); + + if (v4l2sink->num_buffers != v4l2sink->pool->buffer_count) { + v4l2sink->num_buffers = v4l2sink->pool->buffer_count; + g_object_notify (G_OBJECT (v4l2sink), "queue-size"); + } + } + + v4l2buf = gst_v4l2_buffer_pool_get (v4l2sink->pool, TRUE); + + if (G_LIKELY (v4l2buf)) { + GST_DEBUG_OBJECT (v4l2sink, "allocated buffer: %p", v4l2buf); + *buf = GST_BUFFER (v4l2buf); + return GST_FLOW_OK; + } else { + GST_DEBUG_OBJECT (v4l2sink, "failed to allocate buffer"); + return GST_FLOW_ERROR; + } + + } else { + GST_ERROR_OBJECT (v4l2sink, "only supporting streaming mode for now..."); + return GST_FLOW_ERROR; + } +} + +/* called after A/V sync to render frame */ +static GstFlowReturn +gst_v4l2sink_show_frame (GstBaseSink * bsink, GstBuffer * buf) +{ + GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink); + GstBuffer *newbuf = NULL; + + GST_DEBUG_OBJECT (v4l2sink, "render buffer: %p", buf); + + if (!GST_IS_V4L2_BUFFER (buf)) { + GstFlowReturn ret; + + /* special case check for sub-buffers: In certain cases, places like + * GstBaseTransform, which might check that the buffer is writable + * before copying metadata, timestamp, and such, will find that the + * buffer has more than one reference to it. In these cases, they + * will create a sub-buffer with an offset=0 and length equal to the + * original buffer size. + * + * This could happen in two scenarios: (1) a tee in the pipeline, and + * (2) because the refcnt is incremented in gst_mini_object_free() + * before the finalize function is called, and decremented after it + * returns.. but returning this buffer to the buffer pool in the + * finalize function, could wake up a thread blocked in _buffer_alloc() + * which could run and get a buffer w/ refcnt==2 before the thread + * originally unref'ing the buffer returns from finalize function and + * decrements the refcnt back to 1! + */ + if (buf->parent && + (GST_BUFFER_DATA (buf) == GST_BUFFER_DATA (buf->parent)) && + (GST_BUFFER_SIZE (buf) == GST_BUFFER_SIZE (buf->parent))) { + GST_DEBUG_OBJECT (v4l2sink, "I have a sub-buffer!"); + return gst_v4l2sink_show_frame (bsink, buf->parent); + } + + GST_DEBUG_OBJECT (v4l2sink, "slow-path.. I got a %s so I need to memcpy", + g_type_name (G_OBJECT_TYPE (buf))); + + ret = gst_v4l2sink_buffer_alloc (bsink, + GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf), GST_BUFFER_CAPS (buf), + &newbuf); + + if (GST_FLOW_OK != ret) { + GST_DEBUG_OBJECT (v4l2sink, + "dropping frame! Consider increasing 'queue-size' property!"); + return GST_FLOW_OK; + } + + memcpy (GST_BUFFER_DATA (newbuf), + GST_BUFFER_DATA (buf), + MIN (GST_BUFFER_SIZE (newbuf), GST_BUFFER_SIZE (buf))); + + GST_DEBUG_OBJECT (v4l2sink, "render copied buffer: %p", newbuf); + + buf = newbuf; + } + + if (!gst_v4l2_buffer_pool_qbuf (v4l2sink->pool, GST_V4L2_BUFFER (buf))) { + return GST_FLOW_ERROR; + } + if (v4l2sink->state == STATE_PENDING_STREAMON) { + if (!gst_v4l2_object_start_streaming (v4l2sink->v4l2object)) { + return GST_FLOW_ERROR; + } + v4l2sink->state = STATE_STREAMING; + } + + if (!newbuf) { + gst_buffer_ref (buf); + } + + /* if the driver has more than one buffer, ie. more than just the one we + * just queued, then dequeue one immediately to make it available via + * _buffer_alloc(): + */ + if (gst_v4l2_buffer_pool_available_buffers (v4l2sink->pool) > + v4l2sink->min_queued_bufs) { + GstV4l2Buffer *v4l2buf = gst_v4l2_buffer_pool_dqbuf (v4l2sink->pool); + + /* note: if we get a buf, we don't want to use it directly (because + * someone else could still hold a ref).. but instead we release our + * reference to it, and if no one else holds a ref it will be returned + * to the pool of available buffers.. and if not, we keep looping. + */ + if (v4l2buf) { + gst_buffer_unref (GST_BUFFER (v4l2buf)); + } + } + + return GST_FLOW_OK; +} + +#ifdef HAVE_XVIDEO +static void +gst_v4l2sink_navigation_send_event (GstNavigation * navigation, + GstStructure * structure) +{ + GstV4l2Sink *v4l2sink = GST_V4L2SINK (navigation); + GstV4l2Xv *xv = v4l2sink->v4l2object->xv; + GstPad *peer; + + if (!xv) + return; + + if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (v4l2sink)))) { + GstVideoRectangle rect; + gdouble x, y, xscale = 1.0, yscale = 1.0; + + gst_v4l2_xoverlay_get_render_rect (v4l2sink->v4l2object, &rect); + + /* We calculate scaling using the original video frames geometry to + * include pixel aspect ratio scaling. + */ + xscale = (gdouble) v4l2sink->video_width / rect.w; + yscale = (gdouble) v4l2sink->video_height / rect.h; + + /* Converting pointer coordinates to the non scaled geometry */ + if (gst_structure_get_double (structure, "pointer_x", &x)) { + x = MIN (x, rect.x + rect.w); + x = MAX (x - rect.x, 0); + gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, + (gdouble) x * xscale, NULL); + } + if (gst_structure_get_double (structure, "pointer_y", &y)) { + y = MIN (y, rect.y + rect.h); + y = MAX (y - rect.y, 0); + gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, + (gdouble) y * yscale, NULL); + } + + gst_pad_send_event (peer, gst_event_new_navigation (structure)); + gst_object_unref (peer); + } +} +#endif diff --git a/sys/v4l2/gstv4l2sink.h b/sys/v4l2/gstv4l2sink.h new file mode 100644 index 0000000..8fe8222 --- /dev/null +++ b/sys/v4l2/gstv4l2sink.h @@ -0,0 +1,91 @@ +/* GStreamer + * + * Copyright (C) 2009 Texas Instruments, Inc - http://www.ti.com/ + * + * Description: V4L2 sink element + * Created on: Jul 2, 2009 + * Author: Rob Clark <rob@ti.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 __GSTV4L2SINK_H__ +#define __GSTV4L2SINK_H__ + +#include <gst/video/gstvideosink.h> +#include <gstv4l2object.h> +#include <gstv4l2bufferpool.h> + +GST_DEBUG_CATEGORY_EXTERN (v4l2sink_debug); + + +G_BEGIN_DECLS + +#define GST_TYPE_V4L2SINK \ + (gst_v4l2sink_get_type()) +#define GST_V4L2SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_V4L2SINK, GstV4l2Sink)) +#define GST_V4L2SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_V4L2SINK, GstV4l2SinkClass)) +#define GST_IS_V4L2SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_V4L2SINK)) +#define GST_IS_V4L2SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_V4L2SINK)) + +typedef struct _GstV4l2Sink GstV4l2Sink; +typedef struct _GstV4l2SinkClass GstV4l2SinkClass; + + +struct _GstV4l2Sink { + GstVideoSink videosink; + + /*< private >*/ + GstV4l2Object * v4l2object; + GstCaps *probed_caps; /* all supported caps of underlying v4l2 device */ + GstCaps *current_caps; /* the current negotiated caps */ + GstV4l2BufferPool *pool; + guint32 num_buffers; + guint32 min_queued_bufs; + + gint video_width, video_height; /* original (unscaled) video w/h */ + + /* + * field to store requested overlay and crop top/left/width/height props: + * note, could maybe be combined with 'vwin' field in GstV4l2Object? + */ + struct v4l2_rect overlay, crop; + + /* + * bitmask to track which overlay and crop fields user has requested by + * setting properties: + */ + guint8 overlay_fields_set, crop_fields_set; + + guint8 state; +}; + +struct _GstV4l2SinkClass { + GstVideoSinkClass parent_class; + + GList *v4l2_class_devices; +}; + +GType gst_v4l2sink_get_type(void); + +G_END_DECLS + + +#endif /* __GSTV4L2SINK_H__ */ diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c new file mode 100644 index 0000000..f8ae09c --- /dev/null +++ b/sys/v4l2/gstv4l2src.c @@ -0,0 +1,1072 @@ +/* GStreamer + * + * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2src.c: Video4Linux2 source element + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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-v4l2src + * + * v4l2src can be used to capture video from v4l2 devices, like webcams and tv + * cards. + * + * <refsect2> + * <title>Example launch lines</title> + * |[ + * gst-launch v4l2src ! xvimagesink + * ]| This pipeline shows the video captured from /dev/video0 tv card and for + * webcams. + * |[ + * gst-launch v4l2src ! jpegdec ! xvimagesink + * ]| This pipeline shows the video captured from a webcam that delivers jpeg + * images. + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#undef HAVE_XVIDEO + +#include <string.h> +#include <sys/time.h> +#include "v4l2src_calls.h" +#include <unistd.h> + +#include "gstv4l2colorbalance.h" +#include "gstv4l2tuner.h" +#ifdef HAVE_XVIDEO +#include "gstv4l2xoverlay.h" +#endif +#include "gstv4l2vidorient.h" + +#include "gst/gst-i18n-plugin.h" + +GST_DEBUG_CATEGORY (v4l2src_debug); +#define GST_CAT_DEFAULT v4l2src_debug + +#define PROP_DEF_QUEUE_SIZE 2 +#define PROP_DEF_ALWAYS_COPY TRUE +#define PROP_DEF_DECIMATE 1 + +#define DEFAULT_PROP_DEVICE "/dev/video0" + +enum +{ + PROP_0, + V4L2_STD_OBJECT_PROPS, + PROP_QUEUE_SIZE, + PROP_ALWAYS_COPY, + PROP_DECIMATE +}; + +GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SrcClass, gst_v4l2src); +GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS (GstV4l2Src, gst_v4l2src); +GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Src, gst_v4l2src); +#ifdef HAVE_XVIDEO +GST_IMPLEMENT_V4L2_XOVERLAY_METHODS (GstV4l2Src, gst_v4l2src); +#endif +GST_IMPLEMENT_V4L2_VIDORIENT_METHODS (GstV4l2Src, gst_v4l2src); + +static void gst_v4l2src_uri_handler_init (gpointer g_iface, + gpointer iface_data); + +static gboolean +gst_v4l2src_iface_supported (GstImplementsInterface * iface, GType iface_type) +{ + GstV4l2Object *v4l2object = GST_V4L2SRC (iface)->v4l2object; + +#ifdef HAVE_XVIDEO + if (!(iface_type == GST_TYPE_TUNER || + iface_type == GST_TYPE_X_OVERLAY || + iface_type == GST_TYPE_COLOR_BALANCE || + iface_type == GST_TYPE_VIDEO_ORIENTATION)) + return FALSE; +#else + if (!(iface_type == GST_TYPE_TUNER || + iface_type == GST_TYPE_COLOR_BALANCE || + iface_type == GST_TYPE_VIDEO_ORIENTATION)) + return FALSE; +#endif + + if (v4l2object->video_fd == -1) + return FALSE; + +#ifdef HAVE_XVIDEO + if (iface_type == GST_TYPE_X_OVERLAY && !GST_V4L2_IS_OVERLAY (v4l2object)) + return FALSE; +#endif + + return TRUE; +} + +static void +gst_v4l2src_interface_init (GstImplementsInterfaceClass * klass) +{ + /* + * default virtual functions + */ + klass->supported = gst_v4l2src_iface_supported; +} + +static void +gst_v4l2src_init_interfaces (GType type) +{ + static const GInterfaceInfo urihandler_info = { + gst_v4l2src_uri_handler_init, + NULL, + NULL + }; + + static const GInterfaceInfo v4l2iface_info = { + (GInterfaceInitFunc) gst_v4l2src_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo v4l2_tuner_info = { + (GInterfaceInitFunc) gst_v4l2src_tuner_interface_init, + NULL, + NULL, + }; +#ifdef HAVE_XVIDEO + /* FIXME: does GstXOverlay for v4l2src make sense in a GStreamer context? */ + static const GInterfaceInfo v4l2_xoverlay_info = { + (GInterfaceInitFunc) gst_v4l2src_xoverlay_interface_init, + NULL, + NULL, + }; +#endif + static const GInterfaceInfo v4l2_colorbalance_info = { + (GInterfaceInitFunc) gst_v4l2src_color_balance_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo v4l2_videoorientation_info = { + (GInterfaceInitFunc) gst_v4l2src_video_orientation_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo v4l2_propertyprobe_info = { + (GInterfaceInitFunc) gst_v4l2src_property_probe_interface_init, + NULL, + NULL, + }; + + g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info); + g_type_add_interface_static (type, + GST_TYPE_IMPLEMENTS_INTERFACE, &v4l2iface_info); + g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l2_tuner_info); +#ifdef HAVE_XVIDEO + g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l2_xoverlay_info); +#endif + g_type_add_interface_static (type, + GST_TYPE_COLOR_BALANCE, &v4l2_colorbalance_info); + g_type_add_interface_static (type, + GST_TYPE_VIDEO_ORIENTATION, &v4l2_videoorientation_info); + g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE, + &v4l2_propertyprobe_info); +} + +GST_BOILERPLATE_FULL (GstV4l2Src, gst_v4l2src, GstPushSrc, GST_TYPE_PUSH_SRC, + gst_v4l2src_init_interfaces); + +static void gst_v4l2src_dispose (GObject * object); +static void gst_v4l2src_finalize (GstV4l2Src * v4l2src); + +/* element methods */ +static GstStateChangeReturn gst_v4l2src_change_state (GstElement * element, + GstStateChange transition); + +/* basesrc methods */ +static gboolean gst_v4l2src_start (GstBaseSrc * src); +static gboolean gst_v4l2src_unlock (GstBaseSrc * src); +static gboolean gst_v4l2src_unlock_stop (GstBaseSrc * src); +static gboolean gst_v4l2src_stop (GstBaseSrc * src); +static gboolean gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps); +static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src); +static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query); +static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** out); +static void gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps); +static gboolean gst_v4l2src_negotiate (GstBaseSrc * basesrc); + +static void gst_v4l2src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_v4l2src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +/* get_frame io methods */ +static GstFlowReturn +gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf); +static GstFlowReturn +gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf); + +static void +gst_v4l2src_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + GstV4l2SrcClass *gstv4l2src_class = GST_V4L2SRC_CLASS (g_class); + GstPadTemplate *pad_template; + + gstv4l2src_class->v4l2_class_devices = NULL; + + GST_DEBUG_CATEGORY_INIT (v4l2src_debug, "v4l2src", 0, "V4L2 source element"); + + gst_element_class_set_details_simple (gstelement_class, + "Video (video4linux2) Source", "Source/Video", + "Reads frames from a Video4Linux2 device", + "Edgard Lima <edgard.lima@indt.org.br>," + " Stefan Kost <ensonic@users.sf.net>"); + + pad_template = + gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + gst_v4l2_object_get_all_caps ()); + gst_element_class_add_pad_template (gstelement_class, pad_template); + gst_object_unref (pad_template); +} + +static void +gst_v4l2src_class_init (GstV4l2SrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *element_class; + GstBaseSrcClass *basesrc_class; + GstPushSrcClass *pushsrc_class; + + gobject_class = G_OBJECT_CLASS (klass); + element_class = GST_ELEMENT_CLASS (klass); + basesrc_class = GST_BASE_SRC_CLASS (klass); + pushsrc_class = GST_PUSH_SRC_CLASS (klass); + + gobject_class->dispose = gst_v4l2src_dispose; + gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2src_finalize; + gobject_class->set_property = gst_v4l2src_set_property; + gobject_class->get_property = gst_v4l2src_get_property; + + element_class->change_state = gst_v4l2src_change_state; + + gst_v4l2_object_install_properties_helper (gobject_class, + DEFAULT_PROP_DEVICE); + g_object_class_install_property (gobject_class, PROP_QUEUE_SIZE, + g_param_spec_uint ("queue-size", "Queue size", + "Number of buffers to be enqueud in the driver in streaming mode", + GST_V4L2_MIN_BUFFERS, GST_V4L2_MAX_BUFFERS, PROP_DEF_QUEUE_SIZE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ALWAYS_COPY, + g_param_spec_boolean ("always-copy", "Always Copy", + "If the buffer will or not be used directly from mmap", + PROP_DEF_ALWAYS_COPY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstV4l2Src:decimate + * + * Only use every nth frame + * + * Since: 0.10.26 + */ + g_object_class_install_property (gobject_class, PROP_DECIMATE, + g_param_spec_int ("decimate", "Decimate", + "Only use every nth frame", 1, G_MAXINT, + PROP_DEF_DECIMATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_v4l2src_get_caps); + basesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_v4l2src_set_caps); + basesrc_class->start = GST_DEBUG_FUNCPTR (gst_v4l2src_start); + basesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_v4l2src_unlock); + basesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_v4l2src_unlock_stop); + basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2src_stop); + basesrc_class->query = GST_DEBUG_FUNCPTR (gst_v4l2src_query); + basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_v4l2src_fixate); + basesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_v4l2src_negotiate); + + pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_v4l2src_create); +} + +static void +gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass) +{ + /* fixme: give an update_fps_function */ + v4l2src->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2src), + V4L2_BUF_TYPE_VIDEO_CAPTURE, DEFAULT_PROP_DEVICE, + gst_v4l2_get_input, gst_v4l2_set_input, NULL); + + /* number of buffers requested */ + v4l2src->num_buffers = PROP_DEF_QUEUE_SIZE; + + v4l2src->always_copy = PROP_DEF_ALWAYS_COPY; + v4l2src->decimate = PROP_DEF_DECIMATE; + + v4l2src->is_capturing = FALSE; + + gst_base_src_set_format (GST_BASE_SRC (v4l2src), GST_FORMAT_TIME); + gst_base_src_set_live (GST_BASE_SRC (v4l2src), TRUE); + + v4l2src->fps_d = 0; + v4l2src->fps_n = 0; +} + + +static void +gst_v4l2src_dispose (GObject * object) +{ + GstV4l2Src *v4l2src = GST_V4L2SRC (object); + + if (v4l2src->probed_caps) { + gst_caps_unref (v4l2src->probed_caps); + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + + +static void +gst_v4l2src_finalize (GstV4l2Src * v4l2src) +{ + gst_v4l2_object_destroy (v4l2src->v4l2object); + + G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (v4l2src)); +} + + +static void +gst_v4l2src_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstV4l2Src *v4l2src = GST_V4L2SRC (object); + + if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object, + prop_id, value, pspec)) { + switch (prop_id) { + case PROP_QUEUE_SIZE: + v4l2src->num_buffers = g_value_get_uint (value); + break; + case PROP_ALWAYS_COPY: + v4l2src->always_copy = g_value_get_boolean (value); + break; + case PROP_DECIMATE: + v4l2src->decimate = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } +} + + +static void +gst_v4l2src_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstV4l2Src *v4l2src = GST_V4L2SRC (object); + + if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object, + prop_id, value, pspec)) { + switch (prop_id) { + case PROP_QUEUE_SIZE: + g_value_set_uint (value, v4l2src->num_buffers); + break; + case PROP_ALWAYS_COPY: + g_value_set_boolean (value, v4l2src->always_copy); + break; + case PROP_DECIMATE: + g_value_set_int (value, v4l2src->decimate); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } +} + + +/* this function is a bit of a last resort */ +static void +gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps) +{ + GstStructure *structure; + gint i; + + GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps); + + for (i = 0; i < gst_caps_get_size (caps); ++i) { + const GValue *v; + + structure = gst_caps_get_structure (caps, i); + + /* FIXME such sizes? we usually fixate to something in the 320x200 + * range... */ + /* We are fixating to greater possble size (limited to GST_V4L2_MAX_SIZE) + and the maximum framerate resolution for that size */ + gst_structure_fixate_field_nearest_int (structure, "width", + GST_V4L2_MAX_SIZE); + gst_structure_fixate_field_nearest_int (structure, "height", + GST_V4L2_MAX_SIZE); + gst_structure_fixate_field_nearest_fraction (structure, "framerate", + G_MAXINT, 1); + + v = gst_structure_get_value (structure, "format"); + if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) { + guint32 fourcc; + + g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST); + + fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0)); + gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL); + } + } + + GST_DEBUG_OBJECT (basesrc, "fixated caps %" GST_PTR_FORMAT, caps); +} + + +static gboolean +gst_v4l2src_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 (GST_BASE_SRC_PAD (basesrc)); + GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps); + LOG_CAPS (basesrc, 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 (GST_BASE_SRC_PAD (basesrc)); + GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps); + LOG_CAPS (basesrc, peercaps); + if (peercaps && !gst_caps_is_any (peercaps)) { + GstCaps *icaps = NULL; + int i; + + /* Prefer the first caps we are compatible with that the peer proposed */ + for (i = 0; i < gst_caps_get_size (peercaps); i++) { + /* get intersection */ + GstCaps *ipcaps = gst_caps_copy_nth (peercaps, i); + + GST_DEBUG_OBJECT (basesrc, "peer: %" GST_PTR_FORMAT, ipcaps); + LOG_CAPS (basesrc, ipcaps); + + icaps = gst_caps_intersect (thiscaps, ipcaps); + gst_caps_unref (ipcaps); + + if (!gst_caps_is_empty (icaps)) + break; + + gst_caps_unref (icaps); + icaps = NULL; + } + + GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, icaps); + LOG_CAPS (basesrc, icaps); + if (icaps) { + /* If there are multiple intersections pick the one with the smallest + * resolution strictly bigger then the first peer caps */ + if (gst_caps_get_size (icaps) > 1) { + GstStructure *s = gst_caps_get_structure (peercaps, 0); + + int best = 0; + + int twidth, theight; + + int width = G_MAXINT, height = G_MAXINT; + + if (gst_structure_get_int (s, "width", &twidth) + && gst_structure_get_int (s, "height", &theight)) { + + /* Walk the structure backwards to get the first entry of the + * smallest resolution bigger (or equal to) the preferred resolution) + */ + for (i = gst_caps_get_size (icaps) - 1; i >= 0; i--) { + GstStructure *is = gst_caps_get_structure (icaps, i); + + int w, h; + + if (gst_structure_get_int (is, "width", &w) + && gst_structure_get_int (is, "height", &h)) { + if (w >= twidth && w <= width && h >= theight && h <= height) { + width = w; + height = h; + best = i; + } + } + } + } + + caps = gst_caps_copy_nth (icaps, best); + gst_caps_unref (icaps); + } else { + caps = icaps; + } + } + gst_caps_unref (thiscaps); + } else { + /* no peer or peer have ANY caps, work with our own caps then */ + caps = thiscaps; + } + if (peercaps) + gst_caps_unref (peercaps); + if (caps) { + 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); + LOG_CAPS (basesrc, 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 */ + if (gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps)) + result = TRUE; + } + } + 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 GstCaps * +gst_v4l2src_get_caps (GstBaseSrc * src) +{ + GstV4l2Src *v4l2src = GST_V4L2SRC (src); + GstCaps *ret; + GSList *walk; + GSList *formats; + + if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) { + /* FIXME: copy? */ + return + gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD + (v4l2src))); + } + + if (v4l2src->probed_caps) + return gst_caps_ref (v4l2src->probed_caps); + + formats = gst_v4l2_object_get_format_list (v4l2src->v4l2object); + + ret = gst_caps_new_empty (); + + for (walk = formats; walk; walk = walk->next) { + struct v4l2_fmtdesc *format; + + GstStructure *template; + + format = (struct v4l2_fmtdesc *) walk->data; + + template = gst_v4l2_object_v4l2fourcc_to_structure (format->pixelformat); + + if (template) { + GstCaps *tmp; + + tmp = + gst_v4l2_object_probe_caps_for_format (v4l2src->v4l2object, + format->pixelformat, template); + if (tmp) + gst_caps_append (ret, tmp); + + gst_structure_free (template); + } else { + GST_DEBUG_OBJECT (v4l2src, "unknown format %u", format->pixelformat); + } + } + + v4l2src->probed_caps = gst_caps_ref (ret); + + GST_INFO_OBJECT (v4l2src, "probed caps: %" GST_PTR_FORMAT, ret); + + return ret; +} + +static gboolean +gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps) +{ + GstV4l2Src *v4l2src; + gint w = 0, h = 0; + gboolean interlaced; + struct v4l2_fmtdesc *format; + guint fps_n, fps_d; + guint size; + + v4l2src = GST_V4L2SRC (src); + + /* if we're not open, punt -- we'll get setcaps'd later via negotiate */ + if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) + return FALSE; + + /* make sure we stop capturing and dealloc buffers */ + if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) { + /* both will throw an element-error on failure */ + if (!gst_v4l2src_capture_stop (v4l2src)) + return FALSE; + if (!gst_v4l2src_capture_deinit (v4l2src)) + return FALSE; + } + + /* we want our own v4l2 type of fourcc codes */ + if (!gst_v4l2_object_get_caps_info (v4l2src->v4l2object, caps, &format, &w, + &h, &interlaced, &fps_n, &fps_d, &size)) { + GST_INFO_OBJECT (v4l2src, + "can't get capture format from caps %" GST_PTR_FORMAT, caps); + return FALSE; + } + + GST_DEBUG_OBJECT (v4l2src, "trying to set_capture %dx%d at %d/%d fps, " + "format %s", w, h, fps_n, fps_d, format->description); + + if (!gst_v4l2src_set_capture (v4l2src, format->pixelformat, w, h, + interlaced, fps_n, fps_d)) + /* error already posted */ + return FALSE; + + if (!gst_v4l2src_capture_init (v4l2src, caps)) + return FALSE; + + if (v4l2src->use_mmap) { + v4l2src->get_frame = gst_v4l2src_get_mmap; + } else { + v4l2src->get_frame = gst_v4l2src_get_read; + } + + if (!gst_v4l2src_capture_start (v4l2src)) + return FALSE; + + /* now store the expected output size */ + v4l2src->frame_byte_size = size; + + return TRUE; +} + +static gboolean +gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query) +{ + GstV4l2Src *src; + + gboolean res = FALSE; + + src = GST_V4L2SRC (bsrc); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_LATENCY:{ + GstClockTime min_latency, max_latency; + + /* device must be open */ + if (!GST_V4L2_IS_OPEN (src->v4l2object)) { + GST_WARNING_OBJECT (src, + "Can't give latency since device isn't open !"); + goto done; + } + + /* we must have a framerate */ + if (src->fps_n <= 0 || src->fps_d <= 0) { + GST_WARNING_OBJECT (src, + "Can't give latency since framerate isn't fixated !"); + goto done; + } + + /* min latency is the time to capture one frame */ + min_latency = + gst_util_uint64_scale_int (GST_SECOND, src->fps_d, src->fps_n); + + /* max latency is total duration of the frame buffer */ + max_latency = src->num_buffers * min_latency; + + GST_DEBUG_OBJECT (bsrc, + "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, + GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); + + /* we are always live, the min latency is 1 frame and the max latency is + * the complete buffer of frames. */ + gst_query_set_latency (query, TRUE, min_latency, max_latency); + + res = TRUE; + break; + } + default: + res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query); + break; + } + +done: + + return res; +} + +/* start and stop are not symmetric -- start will open the device, but not start + * capture. it's setcaps that will start capture, which is called via basesrc's + * negotiate method. stop will both stop capture and close the device. + */ +static gboolean +gst_v4l2src_start (GstBaseSrc * src) +{ + GstV4l2Src *v4l2src = GST_V4L2SRC (src); + + v4l2src->offset = 0; + + /* activate settings for first frame */ + v4l2src->ctrl_time = 0; + gst_object_sync_values (G_OBJECT (src), v4l2src->ctrl_time); + + return TRUE; +} + +static gboolean +gst_v4l2src_unlock (GstBaseSrc * src) +{ + GstV4l2Src *v4l2src = GST_V4L2SRC (src); + + GST_LOG_OBJECT (src, "Flushing"); + gst_poll_set_flushing (v4l2src->v4l2object->poll, TRUE); + + return TRUE; +} + +static gboolean +gst_v4l2src_unlock_stop (GstBaseSrc * src) +{ + GstV4l2Src *v4l2src = GST_V4L2SRC (src); + + GST_LOG_OBJECT (src, "No longer flushing"); + gst_poll_set_flushing (v4l2src->v4l2object->poll, FALSE); + + return TRUE; +} + +static gboolean +gst_v4l2src_stop (GstBaseSrc * src) +{ + GstV4l2Src *v4l2src = GST_V4L2SRC (src); + + if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object) + && !gst_v4l2src_capture_stop (v4l2src)) + return FALSE; + + if (v4l2src->v4l2object->buffer != NULL) { + if (!gst_v4l2src_capture_deinit (v4l2src)) + return FALSE; + } + + v4l2src->fps_d = 0; + v4l2src->fps_n = 0; + + return TRUE; +} + +static GstStateChangeReturn +gst_v4l2src_change_state (GstElement * element, GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstV4l2Src *v4l2src = GST_V4L2SRC (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + /* open the device */ + if (!gst_v4l2_object_start (v4l2src->v4l2object)) + return GST_STATE_CHANGE_FAILURE; + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_NULL: + /* close the device */ + if (!gst_v4l2_object_stop (v4l2src->v4l2object)) + return GST_STATE_CHANGE_FAILURE; + + if (v4l2src->probed_caps) { + gst_caps_unref (v4l2src->probed_caps); + v4l2src->probed_caps = NULL; + } + break; + default: + break; + } + + return ret; +} + +static GstFlowReturn +gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf) +{ + gint amount; + gint ret; + + gint buffersize; + + buffersize = v4l2src->frame_byte_size; + /* In case the size per frame is unknown assume it's a streaming format (e.g. + * mpegts) and grab a reasonable default size instead */ + if (buffersize == 0) + buffersize = GST_BASE_SRC (v4l2src)->blocksize; + + *buf = gst_buffer_new_and_alloc (buffersize); + + do { + ret = gst_poll_wait (v4l2src->v4l2object->poll, GST_CLOCK_TIME_NONE); + if (G_UNLIKELY (ret < 0)) { + if (errno == EBUSY) + goto stopped; + if (errno == ENXIO) { + GST_DEBUG_OBJECT (v4l2src, + "v4l2 device doesn't support polling. Disabling"); + v4l2src->v4l2object->can_poll_device = FALSE; + } else { + if (errno != EAGAIN && errno != EINTR) + goto select_error; + } + } + amount = + v4l2_read (v4l2src->v4l2object->video_fd, GST_BUFFER_DATA (*buf), + buffersize); + if (amount == buffersize) { + break; + } else if (amount == -1) { + if (errno == EAGAIN || errno == EINTR) { + continue; + } else + goto read_error; + } else { + /* short reads can happen if a signal interrupts the read */ + continue; + } + } while (TRUE); + + /* we set the buffer metadata in gst_v4l2src_create() */ + + return GST_FLOW_OK; + + /* ERRORS */ +select_error: + { + GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL), + ("select error %d: %s (%d)", ret, g_strerror (errno), errno)); + return GST_FLOW_ERROR; + } +stopped: + { + GST_DEBUG ("stop called"); + return GST_FLOW_WRONG_STATE; + } +read_error: + { + GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, + (_("Error reading %d bytes from device '%s'."), + buffersize, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM); + gst_buffer_unref (*buf); + return GST_FLOW_ERROR; + } +} + +static GstFlowReturn +gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf) +{ + GstBuffer *temp; + GstFlowReturn ret; + guint size; + guint count = 0; + +again: + ret = gst_v4l2src_grab_frame (v4l2src, &temp); + if (G_UNLIKELY (ret != GST_FLOW_OK)) + goto done; + + if (v4l2src->frame_byte_size > 0) { + size = GST_BUFFER_SIZE (temp); + + /* if size does not match what we expected, try again */ + if (size != v4l2src->frame_byte_size) { + GST_ELEMENT_WARNING (v4l2src, RESOURCE, READ, + (_("Got unexpected frame size of %u instead of %u."), + size, v4l2src->frame_byte_size), (NULL)); + gst_buffer_unref (temp); + if (count++ > 50) + goto size_error; + + goto again; + } + } + + *buf = temp; +done: + return ret; + + /* ERRORS */ +size_error: + { + GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, + (_("Error reading %d bytes on device '%s'."), + v4l2src->frame_byte_size, v4l2src->v4l2object->videodev), (NULL)); + return GST_FLOW_ERROR; + } +} + +static GstFlowReturn +gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf) +{ + GstV4l2Src *v4l2src = GST_V4L2SRC (src); + int i; + GstFlowReturn ret; + + for (i = 0; i < v4l2src->decimate - 1; i++) { + ret = v4l2src->get_frame (v4l2src, buf); + if (ret != GST_FLOW_OK) { + return ret; + } + gst_buffer_unref (*buf); + } + + ret = v4l2src->get_frame (v4l2src, buf); + + /* set buffer metadata */ + if (G_LIKELY (ret == GST_FLOW_OK && *buf)) { + GstClock *clock; + GstClockTime timestamp; + + GST_BUFFER_OFFSET (*buf) = v4l2src->offset++; + GST_BUFFER_OFFSET_END (*buf) = v4l2src->offset; + + /* timestamps, LOCK to get clock and base time. */ + /* FIXME: element clock and base_time is rarely changing */ + GST_OBJECT_LOCK (v4l2src); + if ((clock = GST_ELEMENT_CLOCK (v4l2src))) { + /* we have a clock, get base time and ref clock */ + timestamp = GST_ELEMENT (v4l2src)->base_time; + gst_object_ref (clock); + } else { + /* no clock, can't set timestamps */ + timestamp = GST_CLOCK_TIME_NONE; + } + GST_OBJECT_UNLOCK (v4l2src); + + if (G_LIKELY (clock)) { + /* the time now is the time of the clock minus the base time */ + timestamp = gst_clock_get_time (clock) - timestamp; + gst_object_unref (clock); + + /* if we have a framerate adjust timestamp for frame latency */ + if (GST_CLOCK_TIME_IS_VALID (v4l2src->duration)) { + if (timestamp > v4l2src->duration) + timestamp -= v4l2src->duration; + else + timestamp = 0; + } + } + + /* activate settings for next frame */ + if (GST_CLOCK_TIME_IS_VALID (v4l2src->duration)) { + v4l2src->ctrl_time += v4l2src->duration; + } else { + /* this is not very good (as it should be the next timestamp), + * still good enough for linear fades (as long as it is not -1) + */ + v4l2src->ctrl_time = timestamp; + } + gst_object_sync_values (G_OBJECT (src), v4l2src->ctrl_time); + GST_INFO_OBJECT (src, "sync to %" GST_TIME_FORMAT, + GST_TIME_ARGS (v4l2src->ctrl_time)); + + /* FIXME: use the timestamp from the buffer itself! */ + GST_BUFFER_TIMESTAMP (*buf) = timestamp; + GST_BUFFER_DURATION (*buf) = v4l2src->duration; + } + return ret; +} + + +/* GstURIHandler interface */ +static GstURIType +gst_v4l2src_uri_get_type (void) +{ + return GST_URI_SRC; +} + +static gchar ** +gst_v4l2src_uri_get_protocols (void) +{ + static gchar *protocols[] = { (char *) "v4l2", NULL }; + + return protocols; +} + +static const gchar * +gst_v4l2src_uri_get_uri (GstURIHandler * handler) +{ + GstV4l2Src *v4l2src = GST_V4L2SRC (handler); + + if (v4l2src->v4l2object->videodev != NULL) { + gchar uri[256]; + + /* need to return a const string, but also don't want to leak the generated + * string, so just intern it - there's a limited number of video devices + * after all */ + g_snprintf (uri, sizeof (uri), "v4l2://%s", v4l2src->v4l2object->videodev); + return g_intern_string (uri); + } + + return "v4l2://"; +} + +static gboolean +gst_v4l2src_uri_set_uri (GstURIHandler * handler, const gchar * uri) +{ + GstV4l2Src *v4l2src = GST_V4L2SRC (handler); + const gchar *device = DEFAULT_PROP_DEVICE; + + if (strcmp (uri, "v4l2://") != 0) { + device = uri + 7; + } + g_object_set (v4l2src, "device", device, NULL); + + return TRUE; +} + + +static void +gst_v4l2src_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_v4l2src_uri_get_type; + iface->get_protocols = gst_v4l2src_uri_get_protocols; + iface->get_uri = gst_v4l2src_uri_get_uri; + iface->set_uri = gst_v4l2src_uri_set_uri; +} diff --git a/sys/v4l2/gstv4l2src.h b/sys/v4l2/gstv4l2src.h new file mode 100644 index 0000000..0dd794a --- /dev/null +++ b/sys/v4l2/gstv4l2src.h @@ -0,0 +1,102 @@ +/* GStreamer + * + * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2src.h: BT8x8/V4L2 source element + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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_V4L2SRC_H__ +#define __GST_V4L2SRC_H__ + +#include <gstv4l2object.h> +#include <gstv4l2bufferpool.h> + +GST_DEBUG_CATEGORY_EXTERN (v4l2src_debug); + +G_BEGIN_DECLS + +#define GST_TYPE_V4L2SRC \ + (gst_v4l2src_get_type()) +#define GST_V4L2SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2SRC,GstV4l2Src)) +#define GST_V4L2SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2SRC,GstV4l2SrcClass)) +#define GST_IS_V4L2SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2SRC)) +#define GST_IS_V4L2SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2SRC)) + +typedef struct _GstV4l2Src GstV4l2Src; +typedef struct _GstV4l2SrcClass GstV4l2SrcClass; + +typedef GstFlowReturn (*GstV4l2SrcGetFunc)(GstV4l2Src * v4l2src, GstBuffer ** buf); + +/** + * GstV4l2Src: + * + * Opaque object. + */ +struct _GstV4l2Src +{ + GstPushSrc pushsrc; + + /*< private >*/ + GstV4l2Object * v4l2object; + + /* pads */ + GstCaps *probed_caps; + + /* buffer handling */ + GstV4l2BufferPool *pool; + + guint32 num_buffers; + gboolean use_mmap; + guint32 frame_byte_size; + + /* if the buffer will be or not used from directly mmap */ + gboolean always_copy; + + int decimate; + + /* True if we want to stop */ + gboolean quit; + gboolean is_capturing; + + guint64 offset; + + gint fps_d, fps_n; /* framerate if device is open */ + GstClockTime duration; /* duration of one frame */ + + GstClockTime ctrl_time; + + GstV4l2SrcGetFunc get_frame; +}; + +struct _GstV4l2SrcClass +{ + GstPushSrcClass parent_class; + + GList *v4l2_class_devices; +}; + +GType gst_v4l2src_get_type (void); + +G_END_DECLS + +#endif /* __GST_V4L2SRC_H__ */ diff --git a/sys/v4l2/gstv4l2tuner.c b/sys/v4l2/gstv4l2tuner.c new file mode 100644 index 0000000..a805396 --- /dev/null +++ b/sys/v4l2/gstv4l2tuner.c @@ -0,0 +1,364 @@ +/* GStreamer + * + * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2tuner.c: tuner interface implementation for V4L2 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 "gstv4l2tuner.h" +#include "gstv4l2object.h" +#include "v4l2_calls.h" +#include "v4l2src_calls.h" + +static void gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass * + klass); +static void gst_v4l2_tuner_channel_init (GstV4l2TunerChannel * channel); + +static void gst_v4l2_tuner_norm_class_init (GstV4l2TunerNormClass * klass); +static void gst_v4l2_tuner_norm_init (GstV4l2TunerNorm * norm); + +static GstTunerNormClass *norm_parent_class = NULL; +static GstTunerChannelClass *channel_parent_class = NULL; + +GType +gst_v4l2_tuner_channel_get_type (void) +{ + static GType gst_v4l2_tuner_channel_type = 0; + + if (!gst_v4l2_tuner_channel_type) { + static const GTypeInfo v4l2_tuner_channel_info = { + sizeof (GstV4l2TunerChannelClass), + NULL, + NULL, + (GClassInitFunc) gst_v4l2_tuner_channel_class_init, + NULL, + NULL, + sizeof (GstV4l2TunerChannel), + 0, + (GInstanceInitFunc) gst_v4l2_tuner_channel_init, + NULL + }; + + gst_v4l2_tuner_channel_type = + g_type_register_static (GST_TYPE_TUNER_CHANNEL, + "GstV4l2TunerChannel", &v4l2_tuner_channel_info, 0); + } + + return gst_v4l2_tuner_channel_type; +} + +static void +gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass * klass) +{ + channel_parent_class = g_type_class_peek_parent (klass); +} + +static void +gst_v4l2_tuner_channel_init (GstV4l2TunerChannel * channel) +{ + channel->index = (guint32) - 1; + channel->tuner = (guint32) - 1; + channel->audio = (guint32) - 1; +} + +GType +gst_v4l2_tuner_norm_get_type (void) +{ + static GType gst_v4l2_tuner_norm_type = 0; + + if (!gst_v4l2_tuner_norm_type) { + static const GTypeInfo v4l2_tuner_norm_info = { + sizeof (GstV4l2TunerNormClass), + NULL, + NULL, + (GClassInitFunc) gst_v4l2_tuner_norm_class_init, + NULL, + NULL, + sizeof (GstV4l2TunerNorm), + 0, + (GInstanceInitFunc) gst_v4l2_tuner_norm_init, + NULL + }; + + gst_v4l2_tuner_norm_type = + g_type_register_static (GST_TYPE_TUNER_NORM, + "GstV4l2TunerNorm", &v4l2_tuner_norm_info, 0); + } + + return gst_v4l2_tuner_norm_type; +} + +static void +gst_v4l2_tuner_norm_class_init (GstV4l2TunerNormClass * klass) +{ + norm_parent_class = g_type_class_peek_parent (klass); +} + +static void +gst_v4l2_tuner_norm_init (GstV4l2TunerNorm * norm) +{ + norm->index = 0; +} + +static G_GNUC_UNUSED gboolean +gst_v4l2_tuner_contains_channel (GstV4l2Object * v4l2object, + GstV4l2TunerChannel * v4l2channel) +{ + const GList *item; + + for (item = v4l2object->channels; item != NULL; item = item->next) + if (item->data == v4l2channel) + return TRUE; + + return FALSE; +} + +const GList * +gst_v4l2_tuner_list_channels (GstV4l2Object * v4l2object) +{ + return v4l2object->channels; +} + +gboolean +gst_v4l2_tuner_set_channel (GstV4l2Object * v4l2object, + GstTunerChannel * channel) +{ + GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE); + g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object, + v4l2channel), FALSE); + + if (v4l2object->set_in_out_func (v4l2object, v4l2channel->index)) { + gst_tuner_channel_changed (GST_TUNER (v4l2object->element), channel); + /* can FPS change here? */ + return TRUE; + } + + return FALSE; + +} + +GstTunerChannel * +gst_v4l2_tuner_get_channel (GstV4l2Object * v4l2object) +{ + GList *item; + gint channel; + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), NULL); + + if (v4l2object->get_in_out_func (v4l2object, &channel)) { + + for (item = v4l2object->channels; item != NULL; item = item->next) { + if (channel == GST_V4L2_TUNER_CHANNEL (item->data)->index) + return (GstTunerChannel *) item->data; + } + + } + + return NULL; +} + +static G_GNUC_UNUSED gboolean +gst_v4l2_tuner_contains_norm (GstV4l2Object * v4l2object, + GstV4l2TunerNorm * v4l2norm) +{ + const GList *item; + + for (item = v4l2object->norms; item != NULL; item = item->next) + if (item->data == v4l2norm) + return TRUE; + + return FALSE; +} + +const GList * +gst_v4l2_tuner_list_norms (GstV4l2Object * v4l2object) +{ + return v4l2object->norms; +} + +void +gst_v4l2_tuner_set_norm_and_notify (GstV4l2Object * v4l2object, + GstTunerNorm * norm) +{ + if (gst_v4l2_tuner_set_norm (v4l2object, norm)) { +#if 0 + g_object_notify (G_OBJECT (v4l2object->element), "norm"); +#endif + } +} + +gboolean +gst_v4l2_tuner_set_norm (GstV4l2Object * v4l2object, GstTunerNorm * norm) +{ + GstV4l2TunerNorm *v4l2norm = GST_V4L2_TUNER_NORM (norm); + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE); + g_return_val_if_fail (gst_v4l2_tuner_contains_norm (v4l2object, v4l2norm), + FALSE); + + if (gst_v4l2_set_norm (v4l2object, v4l2norm->index)) { + gst_tuner_norm_changed (GST_TUNER (v4l2object->element), norm); + if (v4l2object->update_fps_func) + v4l2object->update_fps_func (v4l2object); + return TRUE; + } + + return FALSE; + +} + +GstTunerNorm * +gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object) +{ + v4l2_std_id norm; + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), NULL); + + gst_v4l2_get_norm (v4l2object, &norm); + + return gst_v4l2_tuner_get_norm_by_std_id (v4l2object, norm); +} + +GstTunerNorm * +gst_v4l2_tuner_get_norm_by_std_id (GstV4l2Object * v4l2object, v4l2_std_id norm) +{ + GList *item; + + for (item = v4l2object->norms; item != NULL; item = item->next) { + if (norm & GST_V4L2_TUNER_NORM (item->data)->index) + return (GstTunerNorm *) item->data; + } + + return NULL; +} + +v4l2_std_id +gst_v4l2_tuner_get_std_id_by_norm (GstV4l2Object * v4l2object, + GstTunerNorm * norm) +{ + GList *item; + + for (item = v4l2object->norms; item != NULL; item = item->next) { + if (norm == GST_TUNER_NORM (item->data)) + return GST_V4L2_TUNER_NORM (item->data)->index; + } + + return 0; +} + +void +gst_v4l2_tuner_set_frequency_and_notify (GstV4l2Object * v4l2object, + GstTunerChannel * channel, gulong frequency) +{ + if (gst_v4l2_tuner_set_frequency (v4l2object, channel, frequency)) { +#if 0 + g_object_notify (G_OBJECT (v4l2object->element), "frequency"); +#endif + } +} + +gboolean +gst_v4l2_tuner_set_frequency (GstV4l2Object * v4l2object, + GstTunerChannel * channel, gulong frequency) +{ + GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); + gint chan; + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE); + g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, + GST_TUNER_CHANNEL_FREQUENCY), FALSE); + g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object, + v4l2channel), FALSE); + + if (v4l2object->get_in_out_func (v4l2object, &chan)) { + if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index && + GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { + if (gst_v4l2_set_frequency (v4l2object, v4l2channel->tuner, frequency)) { + gst_tuner_frequency_changed (GST_TUNER (v4l2object->element), channel, + frequency); + return TRUE; + } + } + } + + return FALSE; +} + +gulong +gst_v4l2_tuner_get_frequency (GstV4l2Object * v4l2object, + GstTunerChannel * channel) +{ + GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); + gint chan; + gulong frequency = 0; + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), 0); + g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, + GST_TUNER_CHANNEL_FREQUENCY), 0); + g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object, + v4l2channel), 0); + + if (v4l2object->get_in_out_func (v4l2object, &chan)) { + if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index && + GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { + gst_v4l2_get_frequency (v4l2object, v4l2channel->tuner, &frequency); + } + } + + return frequency; +} + +gint +gst_v4l2_tuner_signal_strength (GstV4l2Object * v4l2object, + GstTunerChannel * channel) +{ + GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); + gint chan; + gulong signal = 0; + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), 0); + g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, + GST_TUNER_CHANNEL_FREQUENCY), 0); + g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object, + v4l2channel), 0); + + if (v4l2object->get_in_out_func (v4l2object, &chan)) { + if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index && + GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { + gst_v4l2_signal_strength (v4l2object, v4l2channel->tuner, &signal); + } + } + + return signal; +} diff --git a/sys/v4l2/gstv4l2tuner.h b/sys/v4l2/gstv4l2tuner.h new file mode 100644 index 0000000..699ca87 --- /dev/null +++ b/sys/v4l2/gstv4l2tuner.h @@ -0,0 +1,198 @@ +/* GStreamer + * + * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2tuner.h: tuner interface implementation for V4L2 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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_V4L2_TUNER_H__ +#define __GST_V4L2_TUNER_H__ + +#include <gst/gst.h> +#include <gst/interfaces/tuner.h> + +#include "gstv4l2object.h" + +G_BEGIN_DECLS + +#define GST_TYPE_V4L2_TUNER_CHANNEL \ + (gst_v4l2_tuner_channel_get_type ()) +#define GST_V4L2_TUNER_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_CHANNEL, \ + GstV4l2TunerChannel)) +#define GST_V4L2_TUNER_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_CHANNEL, \ + GstV4l2TunerChannelClass)) +#define GST_IS_V4L2_TUNER_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_TUNER_CHANNEL)) +#define GST_IS_V4L2_TUNER_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_TUNER_CHANNEL)) + +typedef struct _GstV4l2TunerChannel { + GstTunerChannel parent; + + guint32 index; + guint32 tuner; + guint32 audio; +} GstV4l2TunerChannel; + +typedef struct _GstV4l2TunerChannelClass { + GstTunerChannelClass parent; +} GstV4l2TunerChannelClass; + +#define GST_TYPE_V4L2_TUNER_NORM \ + (gst_v4l2_tuner_norm_get_type ()) +#define GST_V4L2_TUNER_NORM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_NORM, \ + GstV4l2TunerNorm)) +#define GST_V4L2_TUNER_NORM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_NORM, \ + GstV4l2TunerNormClass)) +#define GST_IS_V4L2_TUNER_NORM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_TUNER_NORM)) +#define GST_IS_V4L2_TUNER_NORM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_TUNER_NORM)) + +typedef struct _GstV4l2TunerNorm { + GstTunerNorm parent; + + v4l2_std_id index; +} GstV4l2TunerNorm; + +typedef struct _GstV4l2TunerNormClass { + GstTunerNormClass parent; +} GstV4l2TunerNormClass; + +GType gst_v4l2_tuner_channel_get_type (void); +GType gst_v4l2_tuner_norm_get_type (void); + +/* channels */ +const GList* gst_v4l2_tuner_list_channels (GstV4l2Object * v4l2object); +GstTunerChannel* gst_v4l2_tuner_get_channel (GstV4l2Object * v4l2object); +gboolean gst_v4l2_tuner_set_channel (GstV4l2Object * v4l2object, + GstTunerChannel * channel); +/* norms */ +const GList* gst_v4l2_tuner_list_norms (GstV4l2Object * v4l2object); +void gst_v4l2_tuner_set_norm_and_notify (GstV4l2Object * v4l2object, + GstTunerNorm * norm); +GstTunerNorm* gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object); +gboolean gst_v4l2_tuner_set_norm (GstV4l2Object * v4l2object, + GstTunerNorm * norm); +GstTunerNorm* gst_v4l2_tuner_get_norm_by_std_id (GstV4l2Object * v4l2object, + v4l2_std_id norm); +v4l2_std_id gst_v4l2_tuner_get_std_id_by_norm (GstV4l2Object * v4l2object, + GstTunerNorm * norm); + +/* frequency */ +void gst_v4l2_tuner_set_frequency_and_notify (GstV4l2Object * v4l2object, + GstTunerChannel * channel, + gulong frequency); +gint gst_v4l2_tuner_signal_strength (GstV4l2Object * v4l2object, + GstTunerChannel * channel); +gulong gst_v4l2_tuner_get_frequency (GstV4l2Object * v4l2object, + GstTunerChannel * channel); +gboolean gst_v4l2_tuner_set_frequency (GstV4l2Object * v4l2object, + GstTunerChannel * channel, + gulong frequency); + +#define GST_IMPLEMENT_V4L2_TUNER_METHODS(Type, interface_as_function) \ + \ +static const GList * \ +interface_as_function ## _tuner_list_channels (GstTuner * mixer) \ +{ \ + Type *this = (Type*) mixer; \ + return gst_v4l2_tuner_list_channels (this->v4l2object); \ +} \ + \ +static void \ +interface_as_function ## _tuner_set_channel (GstTuner * mixer, \ + GstTunerChannel * channel) \ +{ \ + Type *this = (Type*) mixer; \ + gst_v4l2_tuner_set_channel (this->v4l2object, channel); \ +} \ +static GstTunerChannel * \ +interface_as_function ## _tuner_get_channel (GstTuner * mixer) \ +{ \ + Type *this = (Type*) mixer; \ + return gst_v4l2_tuner_get_channel (this->v4l2object); \ +} \ +static const GList * \ +interface_as_function ## _tuner_list_norms (GstTuner * mixer) \ +{ \ + Type *this = (Type*) mixer; \ + return gst_v4l2_tuner_list_norms (this->v4l2object); \ +} \ +static void \ +interface_as_function ## _tuner_set_norm_and_notify (GstTuner * mixer, \ + GstTunerNorm * norm) \ +{ \ + Type *this = (Type*) mixer; \ + gst_v4l2_tuner_set_norm_and_notify (this->v4l2object, norm); \ +} \ +static GstTunerNorm * \ +interface_as_function ## _tuner_get_norm (GstTuner * mixer) \ +{ \ + Type *this = (Type*) mixer; \ + return gst_v4l2_tuner_get_norm (this->v4l2object); \ +} \ + \ +static void \ +interface_as_function ## _tuner_set_frequency_and_notify (GstTuner * mixer, \ + GstTunerChannel * channel, \ + gulong frequency) \ +{ \ + Type *this = (Type*) mixer; \ + gst_v4l2_tuner_set_frequency_and_notify (this->v4l2object, channel, frequency); \ +} \ + \ +static gulong \ +interface_as_function ## _tuner_get_frequency (GstTuner * mixer, \ + GstTunerChannel * channel) \ +{ \ + Type *this = (Type*) mixer; \ + return gst_v4l2_tuner_get_frequency (this->v4l2object, channel); \ +} \ + \ +static gint \ +interface_as_function ## _tuner_signal_strength (GstTuner * mixer, \ + GstTunerChannel * channel) \ +{ \ + Type *this = (Type*) mixer; \ + return gst_v4l2_tuner_signal_strength (this->v4l2object, channel); \ +} \ + \ +static void \ +interface_as_function ## _tuner_interface_init (GstTunerClass * klass) \ +{ \ + /* default virtual functions */ \ + klass->list_channels = interface_as_function ## _tuner_list_channels; \ + klass->set_channel = interface_as_function ## _tuner_set_channel; \ + klass->get_channel = interface_as_function ## _tuner_get_channel; \ + \ + klass->list_norms = interface_as_function ## _tuner_list_norms; \ + klass->set_norm = interface_as_function ## _tuner_set_norm_and_notify; \ + klass->get_norm = interface_as_function ## _tuner_get_norm; \ + \ + klass->set_frequency = interface_as_function ## _tuner_set_frequency_and_notify; \ + klass->get_frequency = interface_as_function ## _tuner_get_frequency; \ + klass->signal_strength = interface_as_function ## _tuner_signal_strength; \ +} \ + +#endif /* __GST_V4L2_TUNER_H__ */ diff --git a/sys/v4l2/gstv4l2vidorient.c b/sys/v4l2/gstv4l2vidorient.c new file mode 100644 index 0000000..1fa47e7 --- /dev/null +++ b/sys/v4l2/gstv4l2vidorient.c @@ -0,0 +1,104 @@ +/* GStreamer + * + * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2vidorient.c: video orientation interface implementation for V4L2 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 "gstv4l2vidorient.h" +#include "gstv4l2object.h" +#include "v4l2_calls.h" +#include "v4l2src_calls.h" + +GST_DEBUG_CATEGORY_STATIC (v4l2vo_debug); +#define GST_CAT_DEFAULT v4l2vo_debug + +/* Those are deprecated calls that have been replaced */ +#ifndef V4L2_CID_HCENTER +#define V4L2_CID_HCENTER V4L2_CID_PAN_RESET +#endif +#ifndef V4L2_CID_VCENTER +#define V4L2_CID_VCENTER V4L2_CID_TILT_RESET +#endif + +void +gst_v4l2_video_orientation_interface_init (GstVideoOrientationInterface * klass) +{ + GST_DEBUG_CATEGORY_INIT (v4l2vo_debug, "v4l2vo", 0, + "V4L2 VideoOrientation interface debugging"); +} + + +gboolean +gst_v4l2_video_orientation_get_hflip (GstV4l2Object * v4l2object, + gboolean * flip) +{ + + return gst_v4l2_get_attribute (v4l2object, V4L2_CID_HFLIP, flip); +} + +gboolean +gst_v4l2_video_orientation_get_vflip (GstV4l2Object * v4l2object, + gboolean * flip) +{ + return gst_v4l2_get_attribute (v4l2object, V4L2_CID_VFLIP, flip); +} + +gboolean +gst_v4l2_video_orientation_get_hcenter (GstV4l2Object * v4l2object, + gint * center) +{ + return gst_v4l2_get_attribute (v4l2object, V4L2_CID_HCENTER, center); +} + +gboolean +gst_v4l2_video_orientation_get_vcenter (GstV4l2Object * v4l2object, + gint * center) +{ + return gst_v4l2_get_attribute (v4l2object, V4L2_CID_VCENTER, center); +} + +gboolean +gst_v4l2_video_orientation_set_hflip (GstV4l2Object * v4l2object, gboolean flip) +{ + return gst_v4l2_set_attribute (v4l2object, V4L2_CID_HFLIP, flip); +} + +gboolean +gst_v4l2_video_orientation_set_vflip (GstV4l2Object * v4l2object, gboolean flip) +{ + return gst_v4l2_set_attribute (v4l2object, V4L2_CID_VFLIP, flip); +} + +gboolean +gst_v4l2_video_orientation_set_hcenter (GstV4l2Object * v4l2object, gint center) +{ + return gst_v4l2_set_attribute (v4l2object, V4L2_CID_HCENTER, center); +} + +gboolean +gst_v4l2_video_orientation_set_vcenter (GstV4l2Object * v4l2object, gint center) +{ + return gst_v4l2_set_attribute (v4l2object, V4L2_CID_VCENTER, center); +} diff --git a/sys/v4l2/gstv4l2vidorient.h b/sys/v4l2/gstv4l2vidorient.h new file mode 100644 index 0000000..39682e2 --- /dev/null +++ b/sys/v4l2/gstv4l2vidorient.h @@ -0,0 +1,117 @@ +/* GStreamer + * + * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2vidorient.h: video orientation interface implementation for V4L2 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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_V4L2_VIDORIENT_H__ +#define __GST_V4L2_VIDORIENT_H__ + +#include <gst/gst.h> +#include <gst/interfaces/videoorientation.h> + +#include "gstv4l2object.h" + +G_BEGIN_DECLS + +void gst_v4l2_video_orientation_interface_init (GstVideoOrientationInterface * klass); + +gboolean gst_v4l2_video_orientation_get_hflip (GstV4l2Object *v4l2object, gboolean *flip); +gboolean gst_v4l2_video_orientation_get_vflip (GstV4l2Object *v4l2object, gboolean *flip); +gboolean gst_v4l2_video_orientation_get_hcenter (GstV4l2Object *v4l2object, gint *center); +gboolean gst_v4l2_video_orientation_get_vcenter (GstV4l2Object *v4l2object, gint *center); + +gboolean gst_v4l2_video_orientation_set_hflip (GstV4l2Object *v4l2object, gboolean flip); +gboolean gst_v4l2_video_orientation_set_vflip (GstV4l2Object *v4l2object, gboolean flip); +gboolean gst_v4l2_video_orientation_set_hcenter (GstV4l2Object *v4l2object, gint center); +gboolean gst_v4l2_video_orientation_set_vcenter (GstV4l2Object *v4l2object, gint center); + +#define GST_IMPLEMENT_V4L2_VIDORIENT_METHODS(Type, interface_as_function) \ + \ + static gboolean \ + interface_as_function ## _video_orientation_get_hflip (GstVideoOrientation *vo, gboolean *flip) \ + { \ + Type *this = (Type*) vo; \ + return gst_v4l2_video_orientation_get_hflip (this->v4l2object, flip); \ + } \ + \ + static gboolean \ + interface_as_function ## _video_orientation_get_vflip (GstVideoOrientation *vo, gboolean *flip) \ + { \ + Type *this = (Type*) vo; \ + return gst_v4l2_video_orientation_get_vflip (this->v4l2object, flip); \ + } \ + \ + static gboolean \ + interface_as_function ## _video_orientation_get_hcenter (GstVideoOrientation *vo, gint *center) \ + { \ + Type *this = (Type*) vo; \ + return gst_v4l2_video_orientation_get_hcenter (this->v4l2object, center); \ + } \ + \ + static gboolean \ + interface_as_function ## _video_orientation_get_vcenter (GstVideoOrientation *vo, gint *center) \ + { \ + Type *this = (Type*) vo; \ + return gst_v4l2_video_orientation_get_vcenter (this->v4l2object, center); \ + } \ + \ + static gboolean \ + interface_as_function ## _video_orientation_set_hflip (GstVideoOrientation *vo, gboolean flip) \ + { \ + Type *this = (Type*) vo; \ + return gst_v4l2_video_orientation_set_hflip (this->v4l2object, flip); \ + } \ + \ + static gboolean \ + interface_as_function ## _video_orientation_set_vflip (GstVideoOrientation *vo, gboolean flip) \ + { \ + Type *this = (Type*) vo; \ + return gst_v4l2_video_orientation_set_vflip (this->v4l2object, flip); \ + } \ + \ + static gboolean \ + interface_as_function ## _video_orientation_set_hcenter (GstVideoOrientation *vo, gint center) \ + { \ + Type *this = (Type*) vo; \ + return gst_v4l2_video_orientation_set_hcenter (this->v4l2object, center); \ + } \ + \ + static gboolean \ + interface_as_function ## _video_orientation_set_vcenter (GstVideoOrientation *vo, gint center) \ + { \ + Type *this = (Type*) vo; \ + return gst_v4l2_video_orientation_set_vcenter (this->v4l2object, center); \ + } \ + \ + static void \ + interface_as_function ## _video_orientation_interface_init (GstVideoOrientationInterface * klass) \ + { \ + /* default virtual functions */ \ + klass->get_hflip = interface_as_function ## _video_orientation_get_hflip; \ + klass->get_vflip = interface_as_function ## _video_orientation_get_vflip; \ + klass->get_hcenter = interface_as_function ## _video_orientation_get_hcenter; \ + klass->get_vcenter = interface_as_function ## _video_orientation_get_vcenter; \ + klass->set_hflip = interface_as_function ## _video_orientation_set_hflip; \ + klass->set_vflip = interface_as_function ## _video_orientation_set_vflip; \ + klass->set_hcenter = interface_as_function ## _video_orientation_set_hcenter; \ + klass->set_vcenter = interface_as_function ## _video_orientation_set_vcenter; \ + } + +#endif /* __GST_V4L2_VIDORIENT_H__ */ diff --git a/sys/v4l2/gstv4l2xoverlay.c b/sys/v4l2/gstv4l2xoverlay.c new file mode 100644 index 0000000..60d0919 --- /dev/null +++ b/sys/v4l2/gstv4l2xoverlay.c @@ -0,0 +1,486 @@ +/* GStreamer + * + * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2xoverlay.c: X-based overlay interface implementation for V4L2 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 <X11/X.h> +#include <X11/Xlib.h> +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvlib.h> +#include <sys/stat.h> + +#include <gst/interfaces/navigation.h> + +#include "gstv4l2xoverlay.h" +#include "gstv4l2object.h" +#include "v4l2_calls.h" + +#include "gst/gst-i18n-plugin.h" +#include <gst/glib-compat-private.h> + +struct _GstV4l2Xv +{ + Display *dpy; + gint port, idle_id, event_id; + GMutex *mutex; /* to serialize calls to X11 */ +}; + +GST_DEBUG_CATEGORY_STATIC (v4l2xv_debug); +#define GST_CAT_DEFAULT v4l2xv_debug + +void +gst_v4l2_xoverlay_interface_init (GstXOverlayClass * klass) +{ + GST_DEBUG_CATEGORY_INIT (v4l2xv_debug, "v4l2xv", 0, + "V4L2 XOverlay interface debugging"); +} + +static void +gst_v4l2_xoverlay_open (GstV4l2Object * v4l2object) +{ + struct stat s; + GstV4l2Xv *v4l2xv; + const gchar *name = g_getenv ("DISPLAY"); + unsigned int ver, rel, req, ev, err, anum; + int i, id = 0, first_id = 0, min; + XvAdaptorInfo *ai; + Display *dpy; + + /* we need a display, obviously */ + if (!name || !(dpy = XOpenDisplay (name))) { + GST_WARNING_OBJECT (v4l2object->element, + "No $DISPLAY set or failed to open - no overlay"); + return; + } + + /* First let's check that XVideo extension is available */ + if (!XQueryExtension (dpy, "XVideo", &i, &i, &i)) { + GST_WARNING_OBJECT (v4l2object->element, + "Xv extension not available - no overlay"); + XCloseDisplay (dpy); + return; + } + + /* find port that belongs to this device */ + if (XvQueryExtension (dpy, &ver, &rel, &req, &ev, &err) != Success) { + GST_WARNING_OBJECT (v4l2object->element, + "Xv extension not supported - no overlay"); + XCloseDisplay (dpy); + return; + } + if (XvQueryAdaptors (dpy, DefaultRootWindow (dpy), &anum, &ai) != Success) { + GST_WARNING_OBJECT (v4l2object->element, "Failed to query Xv adaptors"); + XCloseDisplay (dpy); + return; + } + if (fstat (v4l2object->video_fd, &s) < 0) { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, + (_("Cannot identify device '%s'."), v4l2object->videodev), + GST_ERROR_SYSTEM); + XCloseDisplay (dpy); + return; + } + min = s.st_rdev & 0xff; + for (i = 0; i < anum; i++) { + GST_DEBUG_OBJECT (v4l2object->element, "found adapter: %s", ai[i].name); + if (!strcmp (ai[i].name, "video4linux2") || + !strcmp (ai[i].name, "video4linux")) { + if (first_id == 0) + first_id = ai[i].base_id; + + GST_DEBUG_OBJECT (v4l2object->element, + "first_id=%d, base_id=%lu, min=%d", first_id, ai[i].base_id, min); + + /* hmm... */ + if (first_id != 0 && ai[i].base_id == first_id + min) + id = ai[i].base_id; + } + } + XvFreeAdaptorInfo (ai); + + if (id == 0) { + GST_WARNING_OBJECT (v4l2object->element, + "Did not find XvPortID for device - no overlay"); + XCloseDisplay (dpy); + return; + } + + v4l2xv = g_new0 (GstV4l2Xv, 1); + v4l2xv->dpy = dpy; + v4l2xv->port = id; + v4l2xv->mutex = g_mutex_new (); + v4l2xv->idle_id = 0; + v4l2xv->event_id = 0; + v4l2object->xv = v4l2xv; + + if (v4l2object->xwindow_id) { + gst_v4l2_xoverlay_set_window_handle (v4l2object, v4l2object->xwindow_id); + } +} + +static void +gst_v4l2_xoverlay_close (GstV4l2Object * v4l2object) +{ + GstV4l2Xv *v4l2xv = v4l2object->xv; + + if (!v4l2object->xv) + return; + + if (v4l2object->xwindow_id) { + gst_v4l2_xoverlay_set_window_handle (v4l2object, 0); + } + + XCloseDisplay (v4l2xv->dpy); + g_mutex_free (v4l2xv->mutex); + if (v4l2xv->idle_id) + g_source_remove (v4l2xv->idle_id); + if (v4l2xv->event_id) + g_source_remove (v4l2xv->event_id); + g_free (v4l2xv); + v4l2object->xv = NULL; +} + +void +gst_v4l2_xoverlay_start (GstV4l2Object * v4l2object) +{ + if (v4l2object->xwindow_id) { + gst_v4l2_xoverlay_open (v4l2object); + } +} + +void +gst_v4l2_xoverlay_stop (GstV4l2Object * v4l2object) +{ + gst_v4l2_xoverlay_close (v4l2object); +} + +/* should be called with mutex held */ +static gboolean +get_render_rect (GstV4l2Object * v4l2object, GstVideoRectangle * rect) +{ + GstV4l2Xv *v4l2xv = v4l2object->xv; + if (v4l2xv && v4l2xv->dpy && v4l2object->xwindow_id) { + XWindowAttributes attr; + XGetWindowAttributes (v4l2xv->dpy, v4l2object->xwindow_id, &attr); + /* this is where we'd add support to maintain aspect ratio */ + rect->x = 0; + rect->y = 0; + rect->w = attr.width; + rect->h = attr.height; + return TRUE; + } else { + return FALSE; + } +} + +gboolean +gst_v4l2_xoverlay_get_render_rect (GstV4l2Object * v4l2object, + GstVideoRectangle * rect) +{ + GstV4l2Xv *v4l2xv = v4l2object->xv; + gboolean ret = FALSE; + if (v4l2xv) { + g_mutex_lock (v4l2xv->mutex); + ret = get_render_rect (v4l2object, rect); + g_mutex_unlock (v4l2xv->mutex); + } + return ret; +} + +static void +update_geometry (GstV4l2Object * v4l2object) +{ + GstV4l2Xv *v4l2xv = v4l2object->xv; + GstVideoRectangle rect; + if (!get_render_rect (v4l2object, &rect)) + return; + /* note: we don't pass in valid video x/y/w/h.. currently the xserver + * doesn't need to know these, as they come from v4l2 by setting the + * crop.. + */ + XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2object->xwindow_id, + DefaultGC (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)), + 0, 0, rect.w, rect.h, rect.x, rect.y, rect.w, rect.h); +} + +static gboolean +idle_refresh (gpointer data) +{ + GstV4l2Object *v4l2object = GST_V4L2_OBJECT (data); + GstV4l2Xv *v4l2xv = v4l2object->xv; + + GST_LOG_OBJECT (v4l2object->element, "idle refresh"); + + if (v4l2xv) { + g_mutex_lock (v4l2xv->mutex); + + update_geometry (v4l2object); + + v4l2xv->idle_id = 0; + g_mutex_unlock (v4l2xv->mutex); + } + + /* once */ + return FALSE; +} + + +static gboolean +event_refresh (gpointer data) +{ + GstV4l2Object *v4l2object = GST_V4L2_OBJECT (data); + GstV4l2Xv *v4l2xv = v4l2object->xv; + + GST_LOG_OBJECT (v4l2object->element, "event refresh"); + + if (v4l2xv) { + XEvent e; + + g_mutex_lock (v4l2xv->mutex); + + /* If the element supports navigation, collect the relavent input + * events and push them upstream as navigation events + */ + if (GST_IS_NAVIGATION (v4l2object->element)) { + guint pointer_x = 0, pointer_y = 0; + gboolean pointer_moved = FALSE; + + /* We get all pointer motion events, only the last position is + * interesting. + */ + while (XCheckWindowEvent (v4l2xv->dpy, v4l2object->xwindow_id, + PointerMotionMask, &e)) { + switch (e.type) { + case MotionNotify: + pointer_x = e.xmotion.x; + pointer_y = e.xmotion.y; + pointer_moved = TRUE; + break; + default: + break; + } + } + if (pointer_moved) { + GST_DEBUG_OBJECT (v4l2object->element, + "pointer moved over window at %d,%d", pointer_x, pointer_y); + g_mutex_unlock (v4l2xv->mutex); + gst_navigation_send_mouse_event (GST_NAVIGATION (v4l2object->element), + "mouse-move", 0, e.xbutton.x, e.xbutton.y); + g_mutex_lock (v4l2xv->mutex); + } + + /* We get all events on our window to throw them upstream + */ + while (XCheckWindowEvent (v4l2xv->dpy, v4l2object->xwindow_id, + KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask, &e)) { + KeySym keysym; + const char *key_str = NULL; + + g_mutex_unlock (v4l2xv->mutex); + + switch (e.type) { + case ButtonPress: + GST_DEBUG_OBJECT (v4l2object->element, + "button %d pressed over window at %d,%d", + e.xbutton.button, e.xbutton.x, e.xbutton.y); + gst_navigation_send_mouse_event (GST_NAVIGATION + (v4l2object->element), "mouse-button-press", e.xbutton.button, + e.xbutton.x, e.xbutton.y); + break; + case ButtonRelease: + GST_DEBUG_OBJECT (v4l2object->element, + "button %d released over window at %d,%d", + e.xbutton.button, e.xbutton.x, e.xbutton.y); + gst_navigation_send_mouse_event (GST_NAVIGATION + (v4l2object->element), "mouse-button-release", e.xbutton.button, + e.xbutton.x, e.xbutton.y); + break; + case KeyPress: + case KeyRelease: + g_mutex_lock (v4l2xv->mutex); + keysym = XKeycodeToKeysym (v4l2xv->dpy, e.xkey.keycode, 0); + if (keysym != NoSymbol) { + key_str = XKeysymToString (keysym); + } else { + key_str = "unknown"; + } + g_mutex_unlock (v4l2xv->mutex); + GST_DEBUG_OBJECT (v4l2object->element, + "key %d pressed over window at %d,%d (%s)", + e.xkey.keycode, e.xkey.x, e.xkey.y, key_str); + gst_navigation_send_key_event (GST_NAVIGATION (v4l2object->element), + e.type == KeyPress ? "key-press" : "key-release", key_str); + break; + default: + GST_DEBUG_OBJECT (v4l2object->element, + "unhandled X event (%d)", e.type); + } + + g_mutex_lock (v4l2xv->mutex); + } + } + + /* Handle ConfigureNotify */ + while (XCheckWindowEvent (v4l2xv->dpy, v4l2object->xwindow_id, + StructureNotifyMask, &e)) { + switch (e.type) { + case ConfigureNotify: + update_geometry (v4l2object); + break; + default: + break; + } + } + g_mutex_unlock (v4l2xv->mutex); + } + + /* repeat */ + return TRUE; +} + +void +gst_v4l2_xoverlay_set_window_handle (GstV4l2Object * v4l2object, guintptr id) +{ + GstV4l2Xv *v4l2xv; + XID xwindow_id = id; + gboolean change = (v4l2object->xwindow_id != xwindow_id); + + GST_LOG_OBJECT (v4l2object->element, "Setting XID to %lx", + (gulong) xwindow_id); + + if (!v4l2object->xv && GST_V4L2_IS_OPEN (v4l2object)) + gst_v4l2_xoverlay_open (v4l2object); + + v4l2xv = v4l2object->xv; + + if (v4l2xv) + g_mutex_lock (v4l2xv->mutex); + + if (change) { + if (v4l2object->xwindow_id && v4l2xv) { + GST_DEBUG_OBJECT (v4l2object->element, + "Deactivating old port %lx", v4l2object->xwindow_id); + + XvSelectPortNotify (v4l2xv->dpy, v4l2xv->port, 0); + XvSelectVideoNotify (v4l2xv->dpy, v4l2object->xwindow_id, 0); + XvStopVideo (v4l2xv->dpy, v4l2xv->port, v4l2object->xwindow_id); + } + + v4l2object->xwindow_id = xwindow_id; + } + + if (!v4l2xv || xwindow_id == 0) { + if (v4l2xv) + g_mutex_unlock (v4l2xv->mutex); + return; + } + + if (change) { + GST_DEBUG_OBJECT (v4l2object->element, "Activating new port %lx", + xwindow_id); + + /* draw */ + XvSelectPortNotify (v4l2xv->dpy, v4l2xv->port, 1); + XvSelectVideoNotify (v4l2xv->dpy, v4l2object->xwindow_id, 1); + } + + update_geometry (v4l2object); + + if (v4l2xv->idle_id) + g_source_remove (v4l2xv->idle_id); + v4l2xv->idle_id = g_idle_add (idle_refresh, v4l2object); + g_mutex_unlock (v4l2xv->mutex); +} + +/** + * gst_v4l2_xoverlay_prepare_xwindow_id: + * @v4l2object: the v4l2object + * @required: %TRUE if display is required (ie. TRUE for v4l2sink, but + * FALSE for any other element with optional overlay capabilities) + * + * Helper function to create a windo if none is set from the application. + */ +void +gst_v4l2_xoverlay_prepare_xwindow_id (GstV4l2Object * v4l2object, + gboolean required) +{ + if (!GST_V4L2_IS_OVERLAY (v4l2object)) + return; + + gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (v4l2object->element)); + + if (required && !v4l2object->xwindow_id) { + GstV4l2Xv *v4l2xv; + Window win; + int width, height; + long event_mask; + + if (!v4l2object->xv && GST_V4L2_IS_OPEN (v4l2object)) + gst_v4l2_xoverlay_open (v4l2object); + + v4l2xv = v4l2object->xv; + + /* if xoverlay is not supported, just bail */ + if (!v4l2xv) + return; + + /* xoverlay is supported, but we don't have a window.. so create one */ + GST_DEBUG_OBJECT (v4l2object->element, "creating window"); + + g_mutex_lock (v4l2xv->mutex); + + width = XDisplayWidth (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)); + height = XDisplayHeight (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)); + GST_DEBUG_OBJECT (v4l2object->element, "dpy=%p", v4l2xv->dpy); + + win = XCreateSimpleWindow (v4l2xv->dpy, + DefaultRootWindow (v4l2xv->dpy), + 0, 0, width, height, 0, 0, + XBlackPixel (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy))); + + GST_DEBUG_OBJECT (v4l2object->element, "win=%lu", win); + + event_mask = ExposureMask | StructureNotifyMask; + if (GST_IS_NAVIGATION (v4l2object->element)) { + event_mask |= PointerMotionMask | + KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask; + } + XSelectInput (v4l2xv->dpy, win, event_mask); + v4l2xv->event_id = g_timeout_add (45, event_refresh, v4l2object); + + XMapRaised (v4l2xv->dpy, win); + + XSync (v4l2xv->dpy, FALSE); + + g_mutex_unlock (v4l2xv->mutex); + + GST_DEBUG_OBJECT (v4l2object->element, "got window"); + + gst_v4l2_xoverlay_set_window_handle (v4l2object, win); + } +} diff --git a/sys/v4l2/gstv4l2xoverlay.h b/sys/v4l2/gstv4l2xoverlay.h new file mode 100644 index 0000000..1a09306 --- /dev/null +++ b/sys/v4l2/gstv4l2xoverlay.h @@ -0,0 +1,70 @@ +/* GStreamer + * + * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * gstv4l2xoverlay.h: tv mixer interface implementation for V4L2 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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_V4L2_X_OVERLAY_H__ +#define __GST_V4L2_X_OVERLAY_H__ + +#include <X11/X.h> + +#include <gst/gst.h> +#include <gst/interfaces/xoverlay.h> +#include <gst/interfaces/navigation.h> +#include <gst/video/gstvideosink.h> /* for GstVideoRectange */ + +#include "gstv4l2object.h" + +G_BEGIN_DECLS + +void gst_v4l2_xoverlay_start (GstV4l2Object *v4l2object); +void gst_v4l2_xoverlay_stop (GstV4l2Object *v4l2object); +gboolean gst_v4l2_xoverlay_get_render_rect (GstV4l2Object *v4l2object, + GstVideoRectangle *rect); + +void gst_v4l2_xoverlay_interface_init (GstXOverlayClass * klass); +void gst_v4l2_xoverlay_set_window_handle (GstV4l2Object * v4l2object, + guintptr id); +void gst_v4l2_xoverlay_prepare_xwindow_id (GstV4l2Object * v4l2object, + gboolean required); + + +#define GST_IMPLEMENT_V4L2_XOVERLAY_METHODS(Type, interface_as_function) \ + \ +static void \ +interface_as_function ## _xoverlay_set_window_handle (GstXOverlay * xoverlay, \ + guintptr id) \ +{ \ + Type *this = (Type*) xoverlay; \ + gst_v4l2_xoverlay_set_window_handle (this->v4l2object, id); \ +} \ + \ +static void \ +interface_as_function ## _xoverlay_interface_init (GstXOverlayClass * klass) \ +{ \ + /* default virtual functions */ \ + klass->set_window_handle = interface_as_function ## _xoverlay_set_window_handle; \ + \ + gst_v4l2_xoverlay_interface_init(klass); \ +} \ + + +#endif /* __GST_V4L2_X_OVERLAY_H__ */ diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c new file mode 100644 index 0000000..309bfb6 --- /dev/null +++ b/sys/v4l2/v4l2_calls.c @@ -0,0 +1,925 @@ +/* GStreamer + * + * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * v4l2_calls.c - generic V4L2 calls handling + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#ifdef __sun +/* Needed on older Solaris Nevada builds (72 at least) */ +#include <stropts.h> +#include <sys/ioccom.h> +#endif +#include "v4l2_calls.h" +#include "gstv4l2tuner.h" +#if 0 +#include "gstv4l2xoverlay.h" +#endif +#include "gstv4l2colorbalance.h" + +#include "gstv4l2src.h" + +#ifdef HAVE_EXPERIMENTAL +#include "gstv4l2sink.h" +#endif + +#include "gst/gst-i18n-plugin.h" + +/* Those are ioctl calls */ +#ifndef V4L2_CID_HCENTER +#define V4L2_CID_HCENTER V4L2_CID_HCENTER_DEPRECATED +#endif +#ifndef V4L2_CID_VCENTER +#define V4L2_CID_VCENTER V4L2_CID_VCENTER_DEPRECATED +#endif + +GST_DEBUG_CATEGORY_EXTERN (v4l2_debug); +#define GST_CAT_DEFAULT v4l2_debug + +/****************************************************** + * gst_v4l2_get_capabilities(): + * get the device's capturing capabilities + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2_get_capabilities (GstV4l2Object * v4l2object) +{ + GstElement *e; + + e = v4l2object->element; + + GST_DEBUG_OBJECT (e, "getting capabilities"); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &v4l2object->vcap) < 0) + goto cap_failed; + + GST_LOG_OBJECT (e, "driver: '%s'", v4l2object->vcap.driver); + GST_LOG_OBJECT (e, "card: '%s'", v4l2object->vcap.card); + GST_LOG_OBJECT (e, "bus_info: '%s'", v4l2object->vcap.bus_info); + GST_LOG_OBJECT (e, "version: %08x", v4l2object->vcap.version); + GST_LOG_OBJECT (e, "capabilites: %08x", v4l2object->vcap.capabilities); + + return TRUE; + + /* ERRORS */ +cap_failed: + { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, + (_("Error getting capabilities for device '%s': " + "It isn't a v4l2 driver. Check if it is a v4l1 driver."), + v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + + +/****************************************************** + * gst_v4l2_empty_lists() and gst_v4l2_fill_lists(): + * fill/empty the lists of enumerations + * return value: TRUE on success, FALSE on error + ******************************************************/ +static gboolean +gst_v4l2_fill_lists (GstV4l2Object * v4l2object) +{ + gint n; + + GstElement *e; + + e = v4l2object->element; + + GST_DEBUG_OBJECT (e, "getting enumerations"); + GST_V4L2_CHECK_OPEN (v4l2object); + + GST_DEBUG_OBJECT (e, " channels"); + /* and now, the channels */ + for (n = 0;; n++) { + struct v4l2_input input; + GstV4l2TunerChannel *v4l2channel; + GstTunerChannel *channel; + + memset (&input, 0, sizeof (input)); + + input.index = n; + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUMINPUT, &input) < 0) { + if (errno == EINVAL) + break; /* end of enumeration */ + else { + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, + (_("Failed to query attributes of input %d in device %s"), + n, v4l2object->videodev), + ("Failed to get %d in input enumeration for %s. (%d - %s)", + n, v4l2object->videodev, errno, strerror (errno))); + return FALSE; + } + } + + GST_LOG_OBJECT (e, " index: %d", input.index); + GST_LOG_OBJECT (e, " name: '%s'", input.name); + GST_LOG_OBJECT (e, " type: %08x", input.type); + GST_LOG_OBJECT (e, " audioset: %08x", input.audioset); + GST_LOG_OBJECT (e, " std: %016x", (guint) input.std); + GST_LOG_OBJECT (e, " status: %08x", input.status); + + v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL); + channel = GST_TUNER_CHANNEL (v4l2channel); + channel->label = g_strdup ((const gchar *) input.name); + channel->flags = GST_TUNER_CHANNEL_INPUT; + v4l2channel->index = n; + + if (input.type == V4L2_INPUT_TYPE_TUNER) { + struct v4l2_tuner vtun; + + v4l2channel->tuner = input.tuner; + channel->flags |= GST_TUNER_CHANNEL_FREQUENCY; + + vtun.index = input.tuner; + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun) < 0) { + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, + (_("Failed to get setting of tuner %d on device '%s'."), + input.tuner, v4l2object->videodev), GST_ERROR_SYSTEM); + g_object_unref (G_OBJECT (channel)); + return FALSE; + } + + channel->freq_multiplicator = + 62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW) ? 1 : 1000); + channel->min_frequency = vtun.rangelow * channel->freq_multiplicator; + channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator; + channel->min_signal = 0; + channel->max_signal = 0xffff; + } + if (input.audioset) { + /* we take the first. We don't care for + * the others for now */ + while (!(input.audioset & (1 << v4l2channel->audio))) + v4l2channel->audio++; + channel->flags |= GST_TUNER_CHANNEL_AUDIO; + } + + v4l2object->channels = + g_list_prepend (v4l2object->channels, (gpointer) channel); + } + v4l2object->channels = g_list_reverse (v4l2object->channels); + + GST_DEBUG_OBJECT (e, " norms"); + /* norms... */ + for (n = 0;; n++) { + struct v4l2_standard standard = { 0, }; + GstV4l2TunerNorm *v4l2norm; + + GstTunerNorm *norm; + + /* fill in defaults */ + standard.frameperiod.numerator = 1; + standard.frameperiod.denominator = 0; + standard.index = n; + + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUMSTD, &standard) < 0) { + if (errno == EINVAL || errno == ENOTTY) + break; /* end of enumeration */ + else { + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, + (_("Failed to query norm on device '%s'."), + v4l2object->videodev), + ("Failed to get attributes for norm %d on devide '%s'. (%d - %s)", + n, v4l2object->videodev, errno, strerror (errno))); + return FALSE; + } + } + + GST_DEBUG_OBJECT (e, " '%s', fps: %d / %d", + standard.name, standard.frameperiod.denominator, + standard.frameperiod.numerator); + + v4l2norm = g_object_new (GST_TYPE_V4L2_TUNER_NORM, NULL); + norm = GST_TUNER_NORM (v4l2norm); + norm->label = g_strdup ((const gchar *) standard.name); + gst_value_set_fraction (&norm->framerate, + standard.frameperiod.denominator, standard.frameperiod.numerator); + v4l2norm->index = standard.id; + + GST_DEBUG_OBJECT (v4l2object->element, "index=%08x, label=%s", + (unsigned int) v4l2norm->index, norm->label); + + v4l2object->norms = g_list_prepend (v4l2object->norms, (gpointer) norm); + } + v4l2object->norms = g_list_reverse (v4l2object->norms); + + GST_DEBUG_OBJECT (e, " controls+menus"); + + /* and lastly, controls+menus (if appropriate) */ + for (n = V4L2_CID_BASE;; n++) { + struct v4l2_queryctrl control = { 0, }; + GstV4l2ColorBalanceChannel *v4l2channel; + GstColorBalanceChannel *channel; + + /* when we reached the last official CID, continue with private CIDs */ + if (n == V4L2_CID_LASTP1) { + GST_DEBUG_OBJECT (e, "checking private CIDs"); + n = V4L2_CID_PRIVATE_BASE; + } + GST_DEBUG_OBJECT (e, "checking control %08x", n); + + control.id = n; + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCTRL, &control) < 0) { + if (errno == EINVAL || errno == ENOTTY || errno == EIO) { + if (n < V4L2_CID_PRIVATE_BASE) { + GST_DEBUG_OBJECT (e, "skipping control %08x", n); + /* continue so that we also check private controls */ + continue; + } else { + GST_DEBUG_OBJECT (e, "controls finished"); + break; + } + } else { + GST_WARNING_OBJECT (e, "Failed querying control %d on device '%s'. " + "(%d - %s)", n, v4l2object->videodev, errno, strerror (errno)); + continue; + } + } + if (control.flags & V4L2_CTRL_FLAG_DISABLED) { + GST_DEBUG_OBJECT (e, "skipping disabled control"); + continue; + } + + switch (n) { + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_CONTRAST: + case V4L2_CID_SATURATION: + case V4L2_CID_HUE: + case V4L2_CID_BLACK_LEVEL: + case V4L2_CID_AUTO_WHITE_BALANCE: + case V4L2_CID_DO_WHITE_BALANCE: + case V4L2_CID_RED_BALANCE: + case V4L2_CID_BLUE_BALANCE: + case V4L2_CID_GAMMA: + case V4L2_CID_EXPOSURE: + case V4L2_CID_AUTOGAIN: + case V4L2_CID_GAIN: +#ifdef V4L2_CID_SHARPNESS + case V4L2_CID_SHARPNESS: +#endif + /* we only handle these for now (why?) */ + break; + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + case V4L2_CID_HCENTER: + case V4L2_CID_VCENTER: +#ifdef V4L2_CID_PAN_RESET + case V4L2_CID_PAN_RESET: +#endif +#ifdef V4L2_CID_TILT_RESET + case V4L2_CID_TILT_RESET: +#endif + /* not handled here, handled by VideoOrientation interface */ + control.id++; + break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_LOUDNESS: + /* FIXME: We should implement GstMixer interface */ + /* fall through */ + default: + GST_DEBUG_OBJECT (e, + "ControlID %s (%x) unhandled, FIXME", control.name, n); + control.id++; + break; + } + if (n != control.id) + continue; + + GST_DEBUG_OBJECT (e, "Adding ControlID %s (%x)", control.name, n); + v4l2channel = g_object_new (GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, NULL); + channel = GST_COLOR_BALANCE_CHANNEL (v4l2channel); + channel->label = g_strdup ((const gchar *) control.name); + v4l2channel->id = n; + +#if 0 + /* FIXME: it will be need just when handling private controls + *(currently none of base controls are of this type) */ + if (control.type == V4L2_CTRL_TYPE_MENU) { + struct v4l2_querymenu menu, *mptr; + + int i; + + menu.id = n; + for (i = 0;; i++) { + menu.index = i; + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYMENU, &menu) < 0) { + if (errno == EINVAL) + break; /* end of enumeration */ + else { + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, + (_("Failed getting controls attributes on device '%s'."), + v4l2object->videodev), + ("Failed to get %d in menu enumeration for %s. (%d - %s)", + n, v4l2object->videodev, errno, strerror (errno))); + return FALSE; + } + } + mptr = g_malloc (sizeof (menu)); + memcpy (mptr, &menu, sizeof (menu)); + menus = g_list_append (menus, mptr); + } + } + v4l2object->menus = g_list_append (v4l2object->menus, menus); +#endif + + switch (control.type) { + case V4L2_CTRL_TYPE_INTEGER: + channel->min_value = control.minimum; + channel->max_value = control.maximum; + break; + case V4L2_CTRL_TYPE_BOOLEAN: + channel->min_value = FALSE; + channel->max_value = TRUE; + break; + default: + /* FIXME we should find out how to handle V4L2_CTRL_TYPE_BUTTON. + BUTTON controls like V4L2_CID_DO_WHITE_BALANCE can just be set (1) or + unset (0), but can't be queried */ + GST_DEBUG_OBJECT (e, + "Control with non supported type %s (%x), type=%d", + control.name, n, control.type); + channel->min_value = channel->max_value = 0; + break; + } + + v4l2object->colors = + g_list_prepend (v4l2object->colors, (gpointer) channel); + } + v4l2object->colors = g_list_reverse (v4l2object->colors); + + GST_DEBUG_OBJECT (e, "done"); + return TRUE; +} + + +static void +gst_v4l2_empty_lists (GstV4l2Object * v4l2object) +{ + GST_DEBUG_OBJECT (v4l2object->element, "deleting enumerations"); + + g_list_foreach (v4l2object->channels, (GFunc) g_object_unref, NULL); + g_list_free (v4l2object->channels); + v4l2object->channels = NULL; + + g_list_foreach (v4l2object->norms, (GFunc) g_object_unref, NULL); + g_list_free (v4l2object->norms); + v4l2object->norms = NULL; + + g_list_foreach (v4l2object->colors, (GFunc) g_object_unref, NULL); + g_list_free (v4l2object->colors); + v4l2object->colors = NULL; +} + +/****************************************************** + * gst_v4l2_open(): + * open the video device (v4l2object->videodev) + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2_open (GstV4l2Object * v4l2object) +{ + struct stat st; + int libv4l2_fd; + GstPollFD pollfd = GST_POLL_FD_INIT; + + GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s", + v4l2object->videodev); + + GST_V4L2_CHECK_NOT_OPEN (v4l2object); + GST_V4L2_CHECK_NOT_ACTIVE (v4l2object); + + /* be sure we have a device */ + if (!v4l2object->videodev) + v4l2object->videodev = g_strdup ("/dev/video"); + + /* check if it is a device */ + if (stat (v4l2object->videodev, &st) == -1) + goto stat_failed; + + if (!S_ISCHR (st.st_mode)) + goto no_device; + + /* open the device */ + v4l2object->video_fd = + open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ ); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + goto not_open; + + libv4l2_fd = v4l2_fd_open (v4l2object->video_fd, + V4L2_ENABLE_ENUM_FMT_EMULATION); + /* Note the v4l2_xxx functions are designed so that if they get passed an + unknown fd, the will behave exactly as their regular xxx counterparts, so + if v4l2_fd_open fails, we continue as normal (missing the libv4l2 custom + cam format to normal formats conversion). Chances are big we will still + fail then though, as normally v4l2_fd_open only fails if the device is not + a v4l2 device. */ + if (libv4l2_fd != -1) + v4l2object->video_fd = libv4l2_fd; + + v4l2object->can_poll_device = TRUE; + + /* get capabilities, error will be posted */ + if (!gst_v4l2_get_capabilities (v4l2object)) + goto error; + + /* do we need to be a capture device? */ + if (GST_IS_V4L2SRC (v4l2object->element) && + !(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) + goto not_capture; + +#ifdef HAVE_EXPERIMENTAL + if (GST_IS_V4L2SINK (v4l2object->element) && + !(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) + goto not_output; +#endif + + /* create enumerations, posts errors. */ + if (!gst_v4l2_fill_lists (v4l2object)) + goto error; + + GST_INFO_OBJECT (v4l2object->element, + "Opened device '%s' (%s) successfully", + v4l2object->vcap.card, v4l2object->videodev); + + pollfd.fd = v4l2object->video_fd; + gst_poll_add_fd (v4l2object->poll, &pollfd); + gst_poll_fd_ctl_read (v4l2object->poll, &pollfd, TRUE); + + return TRUE; + + /* ERRORS */ +stat_failed: + { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, + (_("Cannot identify device '%s'."), v4l2object->videodev), + GST_ERROR_SYSTEM); + goto error; + } +no_device: + { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, + (_("This isn't a device '%s'."), v4l2object->videodev), + GST_ERROR_SYSTEM); + goto error; + } +not_open: + { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE, + (_("Could not open device '%s' for reading and writing."), + v4l2object->videodev), GST_ERROR_SYSTEM); + goto error; + } +not_capture: + { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, + (_("Device '%s' is not a capture device."), + v4l2object->videodev), + ("Capabilities: 0x%x", v4l2object->vcap.capabilities)); + goto error; + } +#ifdef HAVE_EXPERIMENTAL +not_output: + { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, + (_("Device '%s' is not a output device."), + v4l2object->videodev), + ("Capabilities: 0x%x", v4l2object->vcap.capabilities)); + goto error; + } +#endif +error: + { + if (GST_V4L2_IS_OPEN (v4l2object)) { + /* close device */ + v4l2_close (v4l2object->video_fd); + v4l2object->video_fd = -1; + } + /* empty lists */ + gst_v4l2_empty_lists (v4l2object); + + return FALSE; + } +} + + +/****************************************************** + * gst_v4l2_close(): + * close the video device (v4l2object->video_fd) + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2_close (GstV4l2Object * v4l2object) +{ + GstPollFD pollfd = GST_POLL_FD_INIT; + GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s", + v4l2object->videodev); + + GST_V4L2_CHECK_OPEN (v4l2object); + GST_V4L2_CHECK_NOT_ACTIVE (v4l2object); + + /* close device */ + v4l2_close (v4l2object->video_fd); + pollfd.fd = v4l2object->video_fd; + gst_poll_remove_fd (v4l2object->poll, &pollfd); + v4l2object->video_fd = -1; + + /* empty lists */ + gst_v4l2_empty_lists (v4l2object); + + return TRUE; +} + + +/****************************************************** + * gst_v4l2_get_norm() + * Get the norm of the current device + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm) +{ + GST_DEBUG_OBJECT (v4l2object->element, "getting norm"); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0) + goto std_failed; + + return TRUE; + + /* ERRORS */ +std_failed: + { + GST_DEBUG ("Failed to get the current norm for device %s", + v4l2object->videodev); + return FALSE; + } +} + + +/****************************************************** + * gst_v4l2_set_norm() + * Set the norm of the current device + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm) +{ + GST_DEBUG_OBJECT (v4l2object->element, "trying to set norm to " + "%" G_GINT64_MODIFIER "x", (guint64) norm); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0) + goto std_failed; + + return TRUE; + + /* ERRORS */ +std_failed: + { + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to set norm for device '%s'."), + v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + +/****************************************************** + * gst_v4l2_get_frequency(): + * get the current frequency + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2_get_frequency (GstV4l2Object * v4l2object, + gint tunernum, gulong * frequency) +{ + struct v4l2_frequency freq = { 0, }; + + GstTunerChannel *channel; + + GST_DEBUG_OBJECT (v4l2object->element, "getting current tuner frequency"); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element)); + + freq.tuner = tunernum; + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) + goto freq_failed; + + *frequency = freq.frequency * channel->freq_multiplicator; + + return TRUE; + + /* ERRORS */ +freq_failed: + { + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to get current tuner frequency for device '%s'."), + v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + + +/****************************************************** + * gst_v4l2_set_frequency(): + * set frequency + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2_set_frequency (GstV4l2Object * v4l2object, + gint tunernum, gulong frequency) +{ + struct v4l2_frequency freq = { 0, }; + + GstTunerChannel *channel; + + GST_DEBUG_OBJECT (v4l2object->element, + "setting current tuner frequency to %lu", frequency); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element)); + + freq.tuner = tunernum; + /* fill in type - ignore error */ + v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq); + freq.frequency = frequency / channel->freq_multiplicator; + + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0) + goto freq_failed; + + return TRUE; + + /* ERRORS */ +freq_failed: + { + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to set current tuner frequency for device '%s' to %lu Hz."), + v4l2object->videodev, frequency), GST_ERROR_SYSTEM); + return FALSE; + } +} + +/****************************************************** + * gst_v4l2_signal_strength(): + * get the strength of the signal on the current input + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2_signal_strength (GstV4l2Object * v4l2object, + gint tunernum, gulong * signal_strength) +{ + struct v4l2_tuner tuner = { 0, }; + + GST_DEBUG_OBJECT (v4l2object->element, "trying to get signal strength"); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + tuner.index = tunernum; + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0) + goto tuner_failed; + + *signal_strength = tuner.signal; + + return TRUE; + + /* ERRORS */ +tuner_failed: + { + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to get signal strength for device '%s'."), + v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + +/****************************************************** + * gst_v4l2_get_attribute(): + * try to get the value of one specific attribute + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2_get_attribute (GstV4l2Object * v4l2object, + int attribute_num, int *value) +{ + struct v4l2_control control = { 0, }; + + GST_DEBUG_OBJECT (v4l2object->element, "getting value of attribute %d", + attribute_num); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + control.id = attribute_num; + + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) + goto ctrl_failed; + + *value = control.value; + + return TRUE; + + /* ERRORS */ +ctrl_failed: + { + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to get value for control %d on device '%s'."), + attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + + +/****************************************************** + * gst_v4l2_set_attribute(): + * try to set the value of one specific attribute + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2_set_attribute (GstV4l2Object * v4l2object, + int attribute_num, const int value) +{ + struct v4l2_control control = { 0, }; + + GST_DEBUG_OBJECT (v4l2object->element, "setting value of attribute %d to %d", + attribute_num, value); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + control.id = attribute_num; + control.value = value; + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) + goto ctrl_failed; + + return TRUE; + + /* ERRORS */ +ctrl_failed: + { + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to set value %d for control %d on device '%s'."), + value, attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM); + return FALSE; + } +} + +gboolean +gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input) +{ + gint n; + + GST_DEBUG_OBJECT (v4l2object->element, "trying to get input"); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_INPUT, &n) < 0) + goto input_failed; + + *input = n; + + GST_DEBUG_OBJECT (v4l2object->element, "input: %d", n); + + return TRUE; + + /* ERRORS */ +input_failed: + if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) { + /* only give a warning message if driver actually claims to have tuner + * support + */ + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to get current input on device '%s'. May be it is a radio device"), v4l2object->videodev), GST_ERROR_SYSTEM); + } + return FALSE; +} + +gboolean +gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input) +{ + GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0) + goto input_failed; + + return TRUE; + + /* ERRORS */ +input_failed: + if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) { + /* only give a warning message if driver actually claims to have tuner + * support + */ + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to set input %d on device %s."), + input, v4l2object->videodev), GST_ERROR_SYSTEM); + } + return FALSE; +} + +gboolean +gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output) +{ + gint n; + + GST_DEBUG_OBJECT (v4l2object->element, "trying to get output"); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_OUTPUT, &n) < 0) + goto output_failed; + + *output = n; + + GST_DEBUG_OBJECT (v4l2object->element, "output: %d", n); + + return TRUE; + + /* ERRORS */ +output_failed: + if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) { + /* only give a warning message if driver actually claims to have tuner + * support + */ + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to get current output on device '%s'. May be it is a radio device"), v4l2object->videodev), GST_ERROR_SYSTEM); + } + return FALSE; +} + +gboolean +gst_v4l2_set_output (GstV4l2Object * v4l2object, gint output) +{ + GST_DEBUG_OBJECT (v4l2object->element, "trying to set output to %d", output); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_OUTPUT, &output) < 0) + goto output_failed; + + return TRUE; + + /* ERRORS */ +output_failed: + if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) { + /* only give a warning message if driver actually claims to have tuner + * support + */ + GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, + (_("Failed to set output %d on device %s."), + output, v4l2object->videodev), GST_ERROR_SYSTEM); + } + return FALSE; +} diff --git a/sys/v4l2/v4l2_calls.h b/sys/v4l2/v4l2_calls.h new file mode 100644 index 0000000..d2e2c72 --- /dev/null +++ b/sys/v4l2/v4l2_calls.h @@ -0,0 +1,142 @@ +/* GStreamer + * + * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * v4l2_calls.h - generic V4L2 calls handling + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 __V4L2_CALLS_H__ +#define __V4L2_CALLS_H__ + +#include "gstv4l2object.h" + +#ifdef HAVE_LIBV4L2 +# include <libv4l2.h> +#else +# include <sys/ioctl.h> +# include <linux/videodev2.h> +# define v4l2_fd_open(fd, flags) (fd) +# define v4l2_close close +# define v4l2_dup dup +# define v4l2_ioctl ioctl +# define v4l2_read read +# define v4l2_mmap mmap +# define v4l2_munmap munmap +#endif + +/* simple check whether the device is open */ +#define GST_V4L2_IS_OPEN(v4l2object) \ + (v4l2object->video_fd > 0) + +/* check whether the device is 'active' */ +#define GST_V4L2_IS_ACTIVE(v4l2object) \ + (v4l2object->buffer != NULL) + +#define GST_V4L2_IS_OVERLAY(v4l2object) \ + (v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_OVERLAY) + +/* checks whether the current v4lv4l2object has already been open()'ed or not */ +#define GST_V4L2_CHECK_OPEN(v4l2object) \ + if (!GST_V4L2_IS_OPEN(v4l2object)) \ + { \ + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \ + (_("Device is not open.")), (NULL)); \ + return FALSE; \ + } + +/* checks whether the current v4lv4l2object is close()'ed or whether it is still open */ +#define GST_V4L2_CHECK_NOT_OPEN(v4l2object) \ + if (GST_V4L2_IS_OPEN(v4l2object)) \ + { \ + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \ + (_("Device is open.")), (NULL)); \ + return FALSE; \ + } + +/* checks whether the current v4lv4l2object does video overlay */ +#define GST_V4L2_CHECK_OVERLAY(v4l2object) \ + if (!GST_V4L2_IS_OVERLAY(v4l2object)) \ + { \ + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \ + (NULL), ("Device cannot handle overlay")); \ + return FALSE; \ + } + +/* checks whether we're in capture mode or not */ +#define GST_V4L2_CHECK_ACTIVE(v4l2object) \ + if (!GST_V4L2_IS_ACTIVE(v4l2object)) \ + { \ + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \ + (NULL), ("Device is not in streaming mode")); \ + return FALSE; \ + } + +/* checks whether we're out of capture mode or not */ +#define GST_V4L2_CHECK_NOT_ACTIVE(v4l2object) \ + if (GST_V4L2_IS_ACTIVE(v4l2object)) \ + { \ + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \ + (NULL), ("Device is in streaming mode")); \ + return FALSE; \ + } + + +/* open/close the device */ +gboolean gst_v4l2_open (GstV4l2Object *v4l2object); +gboolean gst_v4l2_close (GstV4l2Object *v4l2object); + +/* norm/input/output */ +gboolean gst_v4l2_get_norm (GstV4l2Object *v4l2object, + v4l2_std_id *norm); +gboolean gst_v4l2_set_norm (GstV4l2Object *v4l2object, + v4l2_std_id norm); +gboolean gst_v4l2_get_input (GstV4l2Object * v4l2object, + gint * input); +gboolean gst_v4l2_set_input (GstV4l2Object * v4l2object, + gint input); +gboolean gst_v4l2_get_output (GstV4l2Object *v4l2object, + gint *output); +gboolean gst_v4l2_set_output (GstV4l2Object *v4l2object, + gint output); + +/* frequency control */ +gboolean gst_v4l2_get_frequency (GstV4l2Object *v4l2object, + gint tunernum, + gulong *frequency); +gboolean gst_v4l2_set_frequency (GstV4l2Object *v4l2object, + gint tunernum, + gulong frequency); +gboolean gst_v4l2_signal_strength (GstV4l2Object *v4l2object, + gint tunernum, + gulong *signal); + +/* attribute control */ +gboolean gst_v4l2_get_attribute (GstV4l2Object *v4l2object, + int attribute, + int *value); +gboolean gst_v4l2_set_attribute (GstV4l2Object *v4l2object, + int attribute, + const int value); + +gboolean gst_v4l2_get_capabilities (GstV4l2Object * v4l2object); + + +#define LOG_CAPS(obj, caps) GST_DEBUG_OBJECT (obj, "%s: %" GST_PTR_FORMAT, #caps, caps) + +#endif /* __V4L2_CALLS_H__ */ diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c new file mode 100644 index 0000000..bfa5589 --- /dev/null +++ b/sys/v4l2/v4l2src_calls.c @@ -0,0 +1,434 @@ +/* GStreamer + * + * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * v4l2src.c - system calls + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <string.h> +#include <errno.h> +#include "v4l2src_calls.h" +#include <sys/time.h> +#include <unistd.h> +#ifdef __sun +/* Needed on older Solaris Nevada builds (72 at least) */ +#include <stropts.h> +#include <sys/ioccom.h> +#endif + +#include "gstv4l2tuner.h" +#include "gstv4l2bufferpool.h" + +#include "gst/gst-i18n-plugin.h" + +#define GST_CAT_DEFAULT v4l2src_debug +GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE); + +/* lalala... */ +#define GST_V4L2_SET_ACTIVE(element) (element)->buffer = GINT_TO_POINTER (-1) +#define GST_V4L2_SET_INACTIVE(element) (element)->buffer = NULL + +/* On some systems MAP_FAILED seems to be missing */ +#ifndef MAP_FAILED +#define MAP_FAILED ((caddr_t) -1) +#endif + + +/* Local functions */ + +static gboolean +gst_v4l2src_buffer_pool_activate (GstV4l2BufferPool * pool, + GstV4l2Src * v4l2src) +{ + GstV4l2Buffer *buf; + + while ((buf = gst_v4l2_buffer_pool_get (pool, FALSE)) != NULL) + if (!gst_v4l2_buffer_pool_qbuf (pool, buf)) + goto queue_failed; + + return TRUE; + + /* ERRORS */ +queue_failed: + { + GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, + (_("Could not enqueue buffers in device '%s'."), + v4l2src->v4l2object->videodev), + ("enqueing buffer %d/%d failed: %s", + buf->vbuffer.index, v4l2src->num_buffers, g_strerror (errno))); + return FALSE; + } +} + +/****************************************************** + * gst_v4l2src_grab_frame (): + * grab a frame for capturing + * return value: GST_FLOW_OK, GST_FLOW_WRONG_STATE or GST_FLOW_ERROR + ******************************************************/ +GstFlowReturn +gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf) +{ +#define NUM_TRIALS 50 + GstV4l2Object *v4l2object; + GstV4l2BufferPool *pool; + gint32 trials = NUM_TRIALS; + GstBuffer *pool_buffer; + gboolean need_copy; + gint ret; + + v4l2object = v4l2src->v4l2object; + pool = v4l2src->pool; + if (!pool) + goto no_buffer_pool; + + GST_DEBUG_OBJECT (v4l2src, "grab frame"); + + for (;;) { + if (v4l2object->can_poll_device) { + ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE); + if (G_UNLIKELY (ret < 0)) { + if (errno == EBUSY) + goto stopped; + if (errno == ENXIO) { + GST_DEBUG_OBJECT (v4l2src, + "v4l2 device doesn't support polling. Disabling"); + v4l2object->can_poll_device = FALSE; + } else { + if (errno != EAGAIN && errno != EINTR) + goto select_error; + } + } + } + + pool_buffer = GST_BUFFER (gst_v4l2_buffer_pool_dqbuf (pool)); + if (pool_buffer) + break; + + GST_WARNING_OBJECT (pool->v4l2elem, "trials=%d", trials); + + /* if the sync() got interrupted, we can retry */ + switch (errno) { + case EINVAL: + case ENOMEM: + /* fatal */ + return GST_FLOW_ERROR; + + case EAGAIN: + case EIO: + case EINTR: + default: + /* try again, until too many trials */ + break; + } + + /* check nr. of attempts to capture */ + if (--trials == -1) { + goto too_many_trials; + } + } + + /* if we are handing out the last buffer in the pool, we need to make a + * copy and bring the buffer back in the pool. */ + need_copy = v4l2src->always_copy + || !gst_v4l2_buffer_pool_available_buffers (pool); + + if (G_UNLIKELY (need_copy)) { + if (!v4l2src->always_copy) { + GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, v4l2src, + "running out of buffers, making a copy to reuse current one"); + } + *buf = gst_buffer_copy (pool_buffer); + GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY); + /* this will requeue */ + gst_buffer_unref (pool_buffer); + } else { + *buf = pool_buffer; + } + /* we set the buffer metadata in gst_v4l2src_create() */ + + return GST_FLOW_OK; + + /* ERRORS */ +no_buffer_pool: + { + GST_DEBUG ("no buffer pool"); + return GST_FLOW_WRONG_STATE; + } +select_error: + { + GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, READ, (NULL), + ("select error %d: %s (%d)", ret, g_strerror (errno), errno)); + return GST_FLOW_ERROR; + } +stopped: + { + GST_DEBUG ("stop called"); + return GST_FLOW_WRONG_STATE; + } +too_many_trials: + { + GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, + (_("Failed trying to get video frames from device '%s'."), + v4l2object->videodev), + (_("Failed after %d tries. device %s. system error: %s"), + NUM_TRIALS, v4l2object->videodev, g_strerror (errno))); + return GST_FLOW_ERROR; + } +} + +/****************************************************** + * gst_v4l2src_set_capture(): + * set capture parameters + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2src_set_capture (GstV4l2Src * v4l2src, guint32 pixelformat, + guint32 width, guint32 height, gboolean interlaced, + guint fps_n, guint fps_d) +{ + gint fd = v4l2src->v4l2object->video_fd; + struct v4l2_streamparm stream; + + if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G')) + return TRUE; + + if (!gst_v4l2_object_set_format (v4l2src->v4l2object, pixelformat, width, + height, interlaced)) { + /* error already reported */ + return FALSE; + } + + /* Is there a reason we require the caller to always specify a framerate? */ + GST_DEBUG_OBJECT (v4l2src, "Desired framerate: %u/%u", fps_n, fps_d); + + memset (&stream, 0x00, sizeof (struct v4l2_streamparm)); + stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (v4l2_ioctl (fd, VIDIOC_G_PARM, &stream) < 0) { + GST_ELEMENT_WARNING (v4l2src, RESOURCE, SETTINGS, + (_("Could not get parameters on device '%s'"), + v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM); + goto done; + } + + /* We used to skip frame rate setup if the camera was already setup + with the requested frame rate. This breaks some cameras though, + causing them to not output data (several models of Thinkpad cameras + have this problem at least). + So, don't skip. */ + + /* We want to change the frame rate, so check whether we can. Some cheap USB + * cameras don't have the capability */ + if ((stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) { + GST_DEBUG_OBJECT (v4l2src, "Not setting framerate (not supported)"); + goto done; + } + + GST_LOG_OBJECT (v4l2src, "Setting framerate to %u/%u", fps_n, fps_d); + + /* Note: V4L2 wants the frame interval, we have the frame rate */ + stream.parm.capture.timeperframe.numerator = fps_d; + stream.parm.capture.timeperframe.denominator = fps_n; + + /* some cheap USB cam's won't accept any change */ + if (v4l2_ioctl (fd, VIDIOC_S_PARM, &stream) < 0) { + GST_ELEMENT_WARNING (v4l2src, RESOURCE, SETTINGS, + (_("Video input device did not accept new frame rate setting.")), + GST_ERROR_SYSTEM); + goto done; + } + + v4l2src->fps_n = fps_n; + v4l2src->fps_d = fps_d; + + /* if we have a framerate pre-calculate duration */ + if (fps_n > 0 && fps_d > 0) { + v4l2src->duration = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n); + } else { + v4l2src->duration = GST_CLOCK_TIME_NONE; + } + + GST_INFO_OBJECT (v4l2src, + "Set framerate to %u/%u and duration to %" GST_TIME_FORMAT, fps_n, fps_d, + GST_TIME_ARGS (v4l2src->duration)); +done: + + return TRUE; +} + +/****************************************************** + * gst_v4l2src_capture_init(): + * initialize the capture system + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2src_capture_init (GstV4l2Src * v4l2src, GstCaps * caps) +{ + GST_DEBUG_OBJECT (v4l2src, "initializing the capture system"); + + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object); + + if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) { + + /* Map the buffers */ + GST_LOG_OBJECT (v4l2src, "initiating buffer pool"); + + if (!(v4l2src->pool = gst_v4l2_buffer_pool_new (GST_ELEMENT (v4l2src), + v4l2src->v4l2object->video_fd, + v4l2src->num_buffers, caps, TRUE, V4L2_BUF_TYPE_VIDEO_CAPTURE))) + goto buffer_pool_new_failed; + + GST_INFO_OBJECT (v4l2src, "capturing buffers via mmap()"); + v4l2src->use_mmap = TRUE; + + if (v4l2src->num_buffers != v4l2src->pool->buffer_count) { + v4l2src->num_buffers = v4l2src->pool->buffer_count; + g_object_notify (G_OBJECT (v4l2src), "queue-size"); + } + + } else if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) { + GST_INFO_OBJECT (v4l2src, "capturing buffers via read()"); + v4l2src->use_mmap = FALSE; + v4l2src->pool = NULL; + } else { + goto no_supported_capture_method; + } + + GST_V4L2_SET_ACTIVE (v4l2src->v4l2object); + + return TRUE; + + /* ERRORS */ +buffer_pool_new_failed: + { + GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, + (_("Could not map buffers from device '%s'"), + v4l2src->v4l2object->videodev), + ("Failed to create buffer pool: %s", g_strerror (errno))); + return FALSE; + } +no_supported_capture_method: + { + GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, + (_("The driver of device '%s' does not support any known capture " + "method."), v4l2src->v4l2object->videodev), (NULL)); + return FALSE; + } +} + + +/****************************************************** + * gst_v4l2src_capture_start(): + * start streaming capture + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2src_capture_start (GstV4l2Src * v4l2src) +{ + GST_DEBUG_OBJECT (v4l2src, "starting the capturing"); + //GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object); + + v4l2src->quit = FALSE; + + if (v4l2src->use_mmap) { + if (!gst_v4l2src_buffer_pool_activate (v4l2src->pool, v4l2src)) { + return FALSE; + } + + if (!gst_v4l2_object_start_streaming (v4l2src->v4l2object)) { + return FALSE; + } + } + + v4l2src->is_capturing = TRUE; + + return TRUE; +} + +/****************************************************** + * gst_v4l2src_capture_stop(): + * stop streaming capture + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2src_capture_stop (GstV4l2Src * v4l2src) +{ + GST_DEBUG_OBJECT (v4l2src, "stopping capturing"); + + if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) { + goto done; + } + if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) { + goto done; + } + + if (v4l2src->use_mmap) { + /* we actually need to sync on all queued buffers but not + * on the non-queued ones */ + if (!gst_v4l2_object_stop_streaming (v4l2src->v4l2object)) { + return FALSE; + } + } + +done: + + /* make an optional pending wait stop */ + v4l2src->quit = TRUE; + v4l2src->is_capturing = FALSE; + + return TRUE; +} + +/****************************************************** + * gst_v4l2src_capture_deinit(): + * deinitialize the capture system + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src) +{ + GST_DEBUG_OBJECT (v4l2src, "deinitting capture system"); + + if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) { + return TRUE; + } + if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) { + return TRUE; + } + + if (v4l2src->pool) { + gst_v4l2_buffer_pool_destroy (v4l2src->pool); + v4l2src->pool = NULL; + } + + GST_V4L2_SET_INACTIVE (v4l2src->v4l2object); + + return TRUE; +} diff --git a/sys/v4l2/v4l2src_calls.h b/sys/v4l2/v4l2src_calls.h new file mode 100644 index 0000000..7091918 --- /dev/null +++ b/sys/v4l2/v4l2src_calls.h @@ -0,0 +1,46 @@ +/* GStreamer + * + * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * v4l2src.h - system calls + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 __V4L2SRC_CALLS_H__ +#define __V4L2SRC_CALLS_H__ + +#include "gstv4l2src.h" +#include "v4l2_calls.h" + +gboolean gst_v4l2src_get_capture (GstV4l2Src * v4l2src); +gboolean gst_v4l2src_set_capture (GstV4l2Src * v4l2src, + guint32 pixelformat, + guint32 width, guint32 height, + gboolean interlaced, + guint32 fps_n, guint32 fps_d); + +gboolean gst_v4l2src_capture_init (GstV4l2Src * v4l2src, GstCaps *caps); +gboolean gst_v4l2src_capture_start (GstV4l2Src * v4l2src); + +GstFlowReturn gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer **buf); + +gboolean gst_v4l2src_capture_stop (GstV4l2Src * v4l2src); +gboolean gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src); + + +#endif /* __V4L2SRC_CALLS_H__ */ diff --git a/sys/waveform/Makefile.am b/sys/waveform/Makefile.am new file mode 100644 index 0000000..a9562a8 --- /dev/null +++ b/sys/waveform/Makefile.am @@ -0,0 +1,20 @@ +plugin_LTLIBRARIES = libgstwaveformsink.la + +# FIXME: Replace DIRECTSOUND CFLAGS+LIBS with waveform related ones and fix +# the configure.ac + sys/Makefile.am to get this stuff building in MingW +# For now, it's just disted for use in the VS builds. + +libgstwaveformsink_la_SOURCES = gstwaveformsink.c gstwaveformplugin.c +libgstwaveformsink_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) $(DIRECTSOUND_CFLAGS) +libgstwaveformsink_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstaudio-$(GST_MAJORMINOR) -lgstinterfaces-$(GST_MAJORMINOR) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) \ + $(DIRECTSOUND_LIBS) +libgstwaveformsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(DIRECTSOUND_LDFLAGS) +libgstwaveformsink_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstwaveformsink.h + diff --git a/sys/waveform/Makefile.in b/sys/waveform/Makefile.in new file mode 100644 index 0000000..efdf5e7 --- /dev/null +++ b/sys/waveform/Makefile.in @@ -0,0 +1,828 @@ +# 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 = sys/waveform +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 = +libgstwaveformsink_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_libgstwaveformsink_la_OBJECTS = \ + libgstwaveformsink_la-gstwaveformsink.lo \ + libgstwaveformsink_la-gstwaveformplugin.lo +libgstwaveformsink_la_OBJECTS = $(am_libgstwaveformsink_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +libgstwaveformsink_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(libgstwaveformsink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(libgstwaveformsink_la_CFLAGS) $(CFLAGS) \ + $(libgstwaveformsink_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 = $(libgstwaveformsink_la_SOURCES) +DIST_SOURCES = $(libgstwaveformsink_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 = libgstwaveformsink.la + +# FIXME: Replace DIRECTSOUND CFLAGS+LIBS with waveform related ones and fix +# the configure.ac + sys/Makefile.am to get this stuff building in MingW +# For now, it's just disted for use in the VS builds. +libgstwaveformsink_la_SOURCES = gstwaveformsink.c gstwaveformplugin.c +libgstwaveformsink_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) $(DIRECTSOUND_CFLAGS) + +libgstwaveformsink_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstaudio-$(GST_MAJORMINOR) -lgstinterfaces-$(GST_MAJORMINOR) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) \ + $(DIRECTSOUND_LIBS) + +libgstwaveformsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(DIRECTSOUND_LDFLAGS) +libgstwaveformsink_la_LIBTOOLFLAGS = --tag=disable-static +noinst_HEADERS = gstwaveformsink.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 sys/waveform/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu sys/waveform/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 +libgstwaveformsink.la: $(libgstwaveformsink_la_OBJECTS) $(libgstwaveformsink_la_DEPENDENCIES) $(EXTRA_libgstwaveformsink_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgstwaveformsink_la_LINK) -rpath $(plugindir) $(libgstwaveformsink_la_OBJECTS) $(libgstwaveformsink_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstwaveformsink_la-gstwaveformplugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstwaveformsink_la-gstwaveformsink.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 $@ $< + +libgstwaveformsink_la-gstwaveformsink.lo: gstwaveformsink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwaveformsink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwaveformsink_la_CFLAGS) $(CFLAGS) -MT libgstwaveformsink_la-gstwaveformsink.lo -MD -MP -MF $(DEPDIR)/libgstwaveformsink_la-gstwaveformsink.Tpo -c -o libgstwaveformsink_la-gstwaveformsink.lo `test -f 'gstwaveformsink.c' || echo '$(srcdir)/'`gstwaveformsink.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstwaveformsink_la-gstwaveformsink.Tpo $(DEPDIR)/libgstwaveformsink_la-gstwaveformsink.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstwaveformsink.c' object='libgstwaveformsink_la-gstwaveformsink.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 $(libgstwaveformsink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwaveformsink_la_CFLAGS) $(CFLAGS) -c -o libgstwaveformsink_la-gstwaveformsink.lo `test -f 'gstwaveformsink.c' || echo '$(srcdir)/'`gstwaveformsink.c + +libgstwaveformsink_la-gstwaveformplugin.lo: gstwaveformplugin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstwaveformsink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwaveformsink_la_CFLAGS) $(CFLAGS) -MT libgstwaveformsink_la-gstwaveformplugin.lo -MD -MP -MF $(DEPDIR)/libgstwaveformsink_la-gstwaveformplugin.Tpo -c -o libgstwaveformsink_la-gstwaveformplugin.lo `test -f 'gstwaveformplugin.c' || echo '$(srcdir)/'`gstwaveformplugin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstwaveformsink_la-gstwaveformplugin.Tpo $(DEPDIR)/libgstwaveformsink_la-gstwaveformplugin.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstwaveformplugin.c' object='libgstwaveformsink_la-gstwaveformplugin.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 $(libgstwaveformsink_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstwaveformsink_la_CFLAGS) $(CFLAGS) -c -o libgstwaveformsink_la-gstwaveformplugin.lo `test -f 'gstwaveformplugin.c' || echo '$(srcdir)/'`gstwaveformplugin.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/sys/waveform/gstwaveformplugin.c b/sys/waveform/gstwaveformplugin.c new file mode 100644 index 0000000..0d7943e --- /dev/null +++ b/sys/waveform/gstwaveformplugin.c @@ -0,0 +1,42 @@ +/* GStreamer +* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net> +* +* gstwaveformplugin.c: +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public +* 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 "gstwaveformsink.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "waveformsink", GST_RANK_PRIMARY, + GST_TYPE_WAVEFORM_SINK)) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "waveform", + "WaveForm win32 API plugin", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/waveform/gstwaveformsink.c b/sys/waveform/gstwaveformsink.c new file mode 100644 index 0000000..0c59829 --- /dev/null +++ b/sys/waveform/gstwaveformsink.c @@ -0,0 +1,585 @@ +/* GStreamer +* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net> +* +* gstwaveformsink.c: +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public +* 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-waveformsink + * + * This element lets you output sound using the Windows WaveForm API. + * + * Note that you should almost always use generic audio conversion elements + * like audioconvert and audioresample in front of an audiosink to make sure + * your pipeline works under all circumstances (those conversion elements will + * act in passthrough-mode if no conversion is necessary). + * + * <refsect2> + * <title>Example pipelines</title> + * |[ + * gst-launch -v audiotestsrc ! audioconvert ! volume volume=0.1 ! waveformsink + * ]| will output a sine wave (continuous beep sound) to your sound card (with + * a very low volume as precaution). + * |[ + * gst-launch -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! waveformsink + * ]| will play an Ogg/Vorbis audio file and output it. + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstwaveformsink.h" + +GST_DEBUG_CATEGORY_STATIC (waveformsink_debug); + +static void gst_waveform_sink_base_init (gpointer g_class); +static void gst_waveform_sink_class_init (GstWaveFormSinkClass * klass); +static void gst_waveform_sink_init (GstWaveFormSink * wfsink, + GstWaveFormSinkClass * g_class); +static void gst_waveform_sink_finalise (GObject * object); +static void gst_waveform_sink_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_waveform_sink_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); +static GstCaps *gst_waveform_sink_getcaps (GstBaseSink * bsink); + +/************************************************************************/ +/* GstAudioSink functions */ +/************************************************************************/ +static gboolean gst_waveform_sink_prepare (GstAudioSink * asink, + GstRingBufferSpec * spec); +static gboolean gst_waveform_sink_unprepare (GstAudioSink * asink); +static gboolean gst_waveform_sink_open (GstAudioSink * asink); +static gboolean gst_waveform_sink_close (GstAudioSink * asink); +static guint gst_waveform_sink_write (GstAudioSink * asink, gpointer data, + guint length); +static guint gst_waveform_sink_delay (GstAudioSink * asink); +static void gst_waveform_sink_reset (GstAudioSink * asink); + +/************************************************************************/ +/* Utils */ +/************************************************************************/ +GstCaps *gst_waveform_sink_create_caps (gint rate, gint channels, + gint bits_per_sample); +WAVEHDR *bufferpool_get_buffer (GstWaveFormSink * wfsink, gpointer data, + guint length); +void CALLBACK waveOutProc (HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, + DWORD_PTR dwParam1, DWORD_PTR dwParam2); + +static GstStaticPadTemplate waveformsink_sink_factory = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "signed = (boolean) { TRUE, FALSE }, " + "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 ]")); + +GST_BOILERPLATE (GstWaveFormSink, gst_waveform_sink, GstAudioSink, + GST_TYPE_AUDIO_SINK); + +static void +gst_waveform_sink_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details_simple (element_class, "WaveForm Audio Sink", + "Sink/Audio", + "Output to a sound card via WaveForm API", + "Sebastien Moutte <sebastien@moutte.net>"); + gst_element_class_add_static_pad_template (element_class, + &waveformsink_sink_factory); +} + +static void +gst_waveform_sink_class_init (GstWaveFormSinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *gstbasesink_class; + GstBaseAudioSinkClass *gstbaseaudiosink_class; + GstAudioSinkClass *gstaudiosink_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesink_class = (GstBaseSinkClass *) klass; + gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass; + gstaudiosink_class = (GstAudioSinkClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->finalize = gst_waveform_sink_finalise; + gobject_class->get_property = gst_waveform_sink_get_property; + gobject_class->set_property = gst_waveform_sink_set_property; + + gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_waveform_sink_getcaps); + + gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_waveform_sink_prepare); + gstaudiosink_class->unprepare = + GST_DEBUG_FUNCPTR (gst_waveform_sink_unprepare); + gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_waveform_sink_open); + gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_waveform_sink_close); + gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_waveform_sink_write); + gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_waveform_sink_delay); + gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_waveform_sink_reset); + + GST_DEBUG_CATEGORY_INIT (waveformsink_debug, "waveformsink", 0, + "Waveform sink"); +} + +static void +gst_waveform_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_waveform_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_waveform_sink_init (GstWaveFormSink * wfsink, + GstWaveFormSinkClass * g_class) +{ + /* initialize members */ + wfsink->hwaveout = NULL; + wfsink->cached_caps = NULL; + wfsink->wave_buffers = NULL; + wfsink->write_buffer = 0; + wfsink->buffer_count = BUFFER_COUNT; + wfsink->buffer_size = BUFFER_SIZE; + wfsink->free_buffers_count = wfsink->buffer_count; + wfsink->bytes_in_queue = 0; + + InitializeCriticalSection (&wfsink->critic_wave); +} + +static void +gst_waveform_sink_finalise (GObject * object) +{ + GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (object); + + if (wfsink->cached_caps) { + gst_caps_unref (wfsink->cached_caps); + wfsink->cached_caps = NULL; + } + + DeleteCriticalSection (&wfsink->critic_wave); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static GstCaps * +gst_waveform_sink_getcaps (GstBaseSink * bsink) +{ + GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (bsink); + MMRESULT mmresult; + WAVEOUTCAPS wocaps; + GstCaps *caps, *caps_temp; + + /* return the cached caps if already defined */ + if (wfsink->cached_caps) { + return gst_caps_ref (wfsink->cached_caps); + } + + /* get the default device caps */ + mmresult = waveOutGetDevCaps (WAVE_MAPPER, &wocaps, sizeof (wocaps)); + if (mmresult != MMSYSERR_NOERROR) { + waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1); + GST_ELEMENT_ERROR (wfsink, RESOURCE, SETTINGS, + ("gst_waveform_sink_getcaps: waveOutGetDevCaps failed error=>%s", + wfsink->error_string), (NULL)); + return NULL; + } + + caps = gst_caps_new_empty (); + + /* create a caps for all wave formats supported by the device + starting by the best quality format */ + if (wocaps.dwFormats & WAVE_FORMAT_96S16) { + caps_temp = gst_waveform_sink_create_caps (96000, 2, 16); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_96S08) { + caps_temp = gst_waveform_sink_create_caps (96000, 2, 8); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_96M16) { + caps_temp = gst_waveform_sink_create_caps (96000, 1, 16); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_96M08) { + caps_temp = gst_waveform_sink_create_caps (96000, 1, 8); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_4S16) { + caps_temp = gst_waveform_sink_create_caps (44100, 2, 16); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_4S08) { + caps_temp = gst_waveform_sink_create_caps (44100, 2, 8); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_4M16) { + caps_temp = gst_waveform_sink_create_caps (44100, 1, 16); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_4M08) { + caps_temp = gst_waveform_sink_create_caps (44100, 1, 8); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_2S16) { + caps_temp = gst_waveform_sink_create_caps (22050, 2, 16); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_2S08) { + caps_temp = gst_waveform_sink_create_caps (22050, 2, 8); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_2M16) { + caps_temp = gst_waveform_sink_create_caps (22050, 1, 16); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_2M08) { + caps_temp = gst_waveform_sink_create_caps (22050, 1, 8); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_1S16) { + caps_temp = gst_waveform_sink_create_caps (11025, 2, 16); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_1S08) { + caps_temp = gst_waveform_sink_create_caps (11025, 2, 8); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_1M16) { + caps_temp = gst_waveform_sink_create_caps (11025, 1, 16); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + if (wocaps.dwFormats & WAVE_FORMAT_1M08) { + caps_temp = gst_waveform_sink_create_caps (11025, 1, 8); + if (caps_temp) { + gst_caps_append (caps, caps_temp); + } + } + + if (gst_caps_is_empty (caps)) { + gst_caps_unref (caps); + caps = NULL; + } else { + wfsink->cached_caps = gst_caps_ref (caps); + } + + GST_CAT_LOG_OBJECT (waveformsink_debug, wfsink, "Returning caps %s", + gst_caps_to_string (caps)); + + return caps; +} + +static gboolean +gst_waveform_sink_open (GstAudioSink * asink) +{ + GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink); + + /* nothing to do here as the device needs to be opened with the format we will use */ + + return TRUE; +} + +static gboolean +gst_waveform_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) +{ + GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink); + WAVEFORMATEX wfx; + MMRESULT mmresult; + guint index; + + /* setup waveformex struture with the input ringbuffer specs */ + memset (&wfx, 0, sizeof (wfx)); + wfx.cbSize = 0; + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = spec->channels; + wfx.nSamplesPerSec = spec->rate; + wfx.wBitsPerSample = (spec->bytes_per_sample * 8) / wfx.nChannels; + wfx.nBlockAlign = spec->bytes_per_sample; + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + + /* save bytes per sample to use it in delay */ + wfsink->bytes_per_sample = spec->bytes_per_sample; + + /* open the default audio device with the given caps */ + mmresult = waveOutOpen (&wfsink->hwaveout, WAVE_MAPPER, + &wfx, (DWORD_PTR) waveOutProc, (DWORD_PTR) wfsink, CALLBACK_FUNCTION); + if (mmresult != MMSYSERR_NOERROR) { + waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1); + GST_ELEMENT_ERROR (wfsink, RESOURCE, OPEN_WRITE, + ("gst_waveform_sink_prepare: waveOutOpen failed error=>%s", + wfsink->error_string), (NULL)); + return FALSE; + } + + /* evaluate the buffer size and the number of buffers needed */ + wfsink->free_buffers_count = wfsink->buffer_count; + + /* allocate wave buffers */ + wfsink->wave_buffers = (WAVEHDR *) g_new0 (WAVEHDR, wfsink->buffer_count); + if (!wfsink->wave_buffers) { + GST_ELEMENT_ERROR (wfsink, RESOURCE, OPEN_WRITE, + ("gst_waveform_sink_prepare: Failed to allocate wave buffer headers (buffer count=%d)", + wfsink->buffer_count), (NULL)); + return FALSE; + } + memset (wfsink->wave_buffers, 0, sizeof (WAVEHDR) * wfsink->buffer_count); + + /* setup headers */ + for (index = 0; index < wfsink->buffer_count; index++) { + wfsink->wave_buffers[index].dwBufferLength = wfsink->buffer_size; + wfsink->wave_buffers[index].lpData = g_new0 (gchar, wfsink->buffer_size); + } + + return TRUE; +} + +static gboolean +gst_waveform_sink_unprepare (GstAudioSink * asink) +{ + GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink); + + /* free wave buffers */ + if (wfsink->wave_buffers) { + guint index; + + for (index = 0; index < wfsink->buffer_count; index++) { + if (wfsink->wave_buffers[index].dwFlags & WHDR_PREPARED) { + MMRESULT mmresult = waveOutUnprepareHeader (wfsink->hwaveout, + &wfsink->wave_buffers[index], sizeof (WAVEHDR)); + if (mmresult != MMSYSERR_NOERROR) { + waveOutGetErrorText (mmresult, wfsink->error_string, + ERROR_LENGTH - 1); + GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink, + "gst_waveform_sink_unprepare: Error unpreparing buffer => %s", + wfsink->error_string); + } + } + g_free (wfsink->wave_buffers[index].lpData); + } + g_free (wfsink->wave_buffers); + wfsink->wave_buffers = NULL; + } + + /* close waveform-audio output device */ + if (wfsink->hwaveout) { + waveOutClose (wfsink->hwaveout); + wfsink->hwaveout = NULL; + } + + return TRUE; +} + +static gboolean +gst_waveform_sink_close (GstAudioSink * asink) +{ + GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink); + + return TRUE; +} + +static guint +gst_waveform_sink_write (GstAudioSink * asink, gpointer data, guint length) +{ + GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink); + WAVEHDR *waveheader; + MMRESULT mmresult; + guint bytes_to_write = length; + guint remaining_length = length; + + wfsink->bytes_in_queue += length; + + while (remaining_length > 0) { + if (wfsink->free_buffers_count == 0) { + /* no free buffer available, wait for one */ + Sleep (10); + continue; + } + + /* get the current write buffer header */ + waveheader = &wfsink->wave_buffers[wfsink->write_buffer]; + + /* unprepare the header if needed */ + if (waveheader->dwFlags & WHDR_PREPARED) { + mmresult = + waveOutUnprepareHeader (wfsink->hwaveout, waveheader, + sizeof (WAVEHDR)); + if (mmresult != MMSYSERR_NOERROR) { + waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1); + GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink, + "Error unpreparing buffer => %s", wfsink->error_string); + } + } + + if (wfsink->buffer_size - waveheader->dwUser >= remaining_length) + bytes_to_write = remaining_length; + else + bytes_to_write = wfsink->buffer_size - waveheader->dwUser; + + memcpy (waveheader->lpData + waveheader->dwUser, data, bytes_to_write); + waveheader->dwUser += bytes_to_write; + remaining_length -= bytes_to_write; + data = (guint8 *) data + bytes_to_write; + + if (waveheader->dwUser == wfsink->buffer_size) { + /* we have filled a buffer, let's prepare it and next write it to the device */ + mmresult = + waveOutPrepareHeader (wfsink->hwaveout, waveheader, sizeof (WAVEHDR)); + if (mmresult != MMSYSERR_NOERROR) { + waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1); + GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink, + "gst_waveform_sink_write: Error preparing header => %s", + wfsink->error_string); + } + mmresult = waveOutWrite (wfsink->hwaveout, waveheader, sizeof (WAVEHDR)); + if (mmresult != MMSYSERR_NOERROR) { + waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1); + GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink, + "gst_waveform_sink_write: Error writting buffer to the device => %s", + wfsink->error_string); + } + + EnterCriticalSection (&wfsink->critic_wave); + wfsink->free_buffers_count--; + LeaveCriticalSection (&wfsink->critic_wave); + + wfsink->write_buffer++; + wfsink->write_buffer %= wfsink->buffer_count; + waveheader->dwUser = 0; + wfsink->bytes_in_queue = 0; + GST_CAT_LOG_OBJECT (waveformsink_debug, wfsink, + "gst_waveform_sink_write: Writting a buffer to the device (free buffers remaining=%d, write buffer=%d)", + wfsink->free_buffers_count, wfsink->write_buffer); + } + } + + return length; +} + +static guint +gst_waveform_sink_delay (GstAudioSink * asink) +{ + /* return the number of samples in queue (device+internal queue) */ + GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink); + guint bytes_in_device = + (wfsink->buffer_count - wfsink->free_buffers_count) * wfsink->buffer_size; + guint delay = + (bytes_in_device + wfsink->bytes_in_queue) / wfsink->bytes_per_sample; + return delay; +} + +static void +gst_waveform_sink_reset (GstAudioSink * asink) +{ + GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink); + MMRESULT mmresult = waveOutReset (wfsink->hwaveout); + + if (mmresult != MMSYSERR_NOERROR) { + waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1); + GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink, + "gst_waveform_sink_reset: Error reseting waveform-audio device => %s", + wfsink->error_string); + } +} + +GstCaps * +gst_waveform_sink_create_caps (gint rate, gint channels, gint bits_per_sample) +{ + GstCaps *caps = NULL; + + caps = gst_caps_new_simple ("audio/x-raw-int", + "width", G_TYPE_INT, bits_per_sample, + "depth", G_TYPE_INT, bits_per_sample, + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "signed", G_TYPE_BOOLEAN, TRUE, + "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, rate, NULL); + return caps; +} + +void CALLBACK +waveOutProc (HWAVEOUT hwo, + UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + GstWaveFormSink *wfsink = (GstWaveFormSink *) dwInstance; + + if (uMsg == WOM_DONE) { + EnterCriticalSection (&wfsink->critic_wave); + wfsink->free_buffers_count++; + LeaveCriticalSection (&wfsink->critic_wave); + } +} diff --git a/sys/waveform/gstwaveformsink.h b/sys/waveform/gstwaveformsink.h new file mode 100644 index 0000000..b23aea1 --- /dev/null +++ b/sys/waveform/gstwaveformsink.h @@ -0,0 +1,107 @@ +/* GStreamer + * Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net> + * + * gstwaveformsink.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_WAVEFORMSINK_H__ +#define __GST_WAVEFORMSINK_H__ + +#include <gst/gst.h> +#include <gst/audio/gstaudiosink.h> + +#include <windows.h> +#include <mmsystem.h> + +#ifndef WAVE_FORMAT_96M08 +#define WAVE_FORMAT_96M08 0x00001000 /* 96 kHz, Mono, 8-bit */ +#endif + +#ifndef WAVE_FORMAT_96S08 +#define WAVE_FORMAT_96S08 0x00002000 /* 96 kHz, Stereo, 8-bit */ +#endif + +#ifndef WAVE_FORMAT_96M16 +#define WAVE_FORMAT_96M16 0x00004000 /* 96 kHz, Mono, 16-bit */ +#endif + +#ifndef WAVE_FORMAT_96S16 +#define WAVE_FORMAT_96S16 0x00008000 /* 96 kHz, Stereo, 16-bit */ +#endif + +#define ERROR_LENGTH MAXERRORLENGTH+50 +#define BUFFER_COUNT 20 +#define BUFFER_SIZE 8192 + +G_BEGIN_DECLS +#define GST_TYPE_WAVEFORM_SINK (gst_waveform_sink_get_type()) +#define GST_WAVEFORM_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVEFORM_SINK,GstWaveFormSink)) +#define GST_WAVEFORM_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVEFORM_SINK,GstWaveFormSinkClass)) +#define GST_IS_WAVEFORM_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVEFORM_SINK)) +#define GST_IS_WAVEFORM_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVEFORM_SINK)) +typedef struct _GstWaveFormSink GstWaveFormSink; +typedef struct _GstWaveFormSinkClass GstWaveFormSinkClass; + +struct _GstWaveFormSink +{ + /* parent object */ + GstAudioSink sink; + + /* supported caps */ + GstCaps *cached_caps; + + /* handle to the waveform-audio output device */ + HWAVEOUT hwaveout; + + /* table of buffer headers */ + WAVEHDR *wave_buffers; + + /* critical section protecting access to the number of free buffers */ + CRITICAL_SECTION critic_wave; + + /* number of free buffers available */ + guint free_buffers_count; + + /* current free buffer where you have to write incoming data */ + guint write_buffer; + + /* size of buffers streamed to the device */ + guint buffer_size; + + /* number of buffers streamed to the device */ + guint buffer_count; + + /* total of bytes in queue before they are written to the device */ + guint bytes_in_queue; + + /* bytes per sample from setcaps used to evaluate the number samples returned by delay */ + guint bytes_per_sample; + + /* wave form error string */ + gchar error_string[ERROR_LENGTH]; +}; + +struct _GstWaveFormSinkClass +{ + GstAudioSinkClass parent_class; +}; + +GType gst_waveform_sink_get_type (void); + +G_END_DECLS +#endif /* __GST_WAVEFORMSINK_H__ */ diff --git a/sys/ximage/Makefile.am b/sys/ximage/Makefile.am new file mode 100644 index 0000000..db3ab22 --- /dev/null +++ b/sys/ximage/Makefile.am @@ -0,0 +1,16 @@ +plugin_LTLIBRARIES = libgstximagesrc.la + +libgstximagesrc_la_SOURCES = gstximagesrc.c ximageutil.c +libgstximagesrc_la_CFLAGS = \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) \ + $(X_CFLAGS) $(XFIXES_CFLAGS) $(XDAMAGE_CFLAGS) +libgstximagesrc_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) \ + $(GST_BASE_LIBS) \ + $(X_LIBS) $(XSHM_LIBS) $(XFIXES_LIBS) $(XDAMAGE_LIBS) +libgstximagesrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstximagesrc_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstximagesrc.h ximageutil.h diff --git a/sys/ximage/Makefile.in b/sys/ximage/Makefile.in new file mode 100644 index 0000000..129f9a8 --- /dev/null +++ b/sys/ximage/Makefile.in @@ -0,0 +1,825 @@ +# 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 = sys/ximage +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 = +libgstximagesrc_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_libgstximagesrc_la_OBJECTS = libgstximagesrc_la-gstximagesrc.lo \ + libgstximagesrc_la-ximageutil.lo +libgstximagesrc_la_OBJECTS = $(am_libgstximagesrc_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +libgstximagesrc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(libgstximagesrc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(libgstximagesrc_la_CFLAGS) $(CFLAGS) \ + $(libgstximagesrc_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 = $(libgstximagesrc_la_SOURCES) +DIST_SOURCES = $(libgstximagesrc_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 = libgstximagesrc.la +libgstximagesrc_la_SOURCES = gstximagesrc.c ximageutil.c +libgstximagesrc_la_CFLAGS = \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) \ + $(X_CFLAGS) $(XFIXES_CFLAGS) $(XDAMAGE_CFLAGS) + +libgstximagesrc_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) \ + $(GST_BASE_LIBS) \ + $(X_LIBS) $(XSHM_LIBS) $(XFIXES_LIBS) $(XDAMAGE_LIBS) + +libgstximagesrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstximagesrc_la_LIBTOOLFLAGS = --tag=disable-static +noinst_HEADERS = gstximagesrc.h ximageutil.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 sys/ximage/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu sys/ximage/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 +libgstximagesrc.la: $(libgstximagesrc_la_OBJECTS) $(libgstximagesrc_la_DEPENDENCIES) $(EXTRA_libgstximagesrc_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgstximagesrc_la_LINK) -rpath $(plugindir) $(libgstximagesrc_la_OBJECTS) $(libgstximagesrc_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstximagesrc_la-gstximagesrc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstximagesrc_la-ximageutil.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 $@ $< + +libgstximagesrc_la-gstximagesrc.lo: gstximagesrc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstximagesrc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstximagesrc_la_CFLAGS) $(CFLAGS) -MT libgstximagesrc_la-gstximagesrc.lo -MD -MP -MF $(DEPDIR)/libgstximagesrc_la-gstximagesrc.Tpo -c -o libgstximagesrc_la-gstximagesrc.lo `test -f 'gstximagesrc.c' || echo '$(srcdir)/'`gstximagesrc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstximagesrc_la-gstximagesrc.Tpo $(DEPDIR)/libgstximagesrc_la-gstximagesrc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstximagesrc.c' object='libgstximagesrc_la-gstximagesrc.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 $(libgstximagesrc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstximagesrc_la_CFLAGS) $(CFLAGS) -c -o libgstximagesrc_la-gstximagesrc.lo `test -f 'gstximagesrc.c' || echo '$(srcdir)/'`gstximagesrc.c + +libgstximagesrc_la-ximageutil.lo: ximageutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstximagesrc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstximagesrc_la_CFLAGS) $(CFLAGS) -MT libgstximagesrc_la-ximageutil.lo -MD -MP -MF $(DEPDIR)/libgstximagesrc_la-ximageutil.Tpo -c -o libgstximagesrc_la-ximageutil.lo `test -f 'ximageutil.c' || echo '$(srcdir)/'`ximageutil.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstximagesrc_la-ximageutil.Tpo $(DEPDIR)/libgstximagesrc_la-ximageutil.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ximageutil.c' object='libgstximagesrc_la-ximageutil.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 $(libgstximagesrc_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstximagesrc_la_CFLAGS) $(CFLAGS) -c -o libgstximagesrc_la-ximageutil.lo `test -f 'ximageutil.c' || echo '$(srcdir)/'`ximageutil.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/sys/ximage/gstximagesrc.c b/sys/ximage/gstximagesrc.c new file mode 100644 index 0000000..36c0b44 --- /dev/null +++ b/sys/ximage/gstximagesrc.c @@ -0,0 +1,1317 @@ +/* GStreamer + * + * Copyright (C) 2006 Zaheer 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-ximagesrc + * + * This element captures your X Display and creates raw RGB video. It uses + * the XDamage extension if available to only capture areas of the screen that + * have changed since the last frame. It uses the XFixes extension if + * available to also capture your mouse pointer. By default it will fixate to + * 25 frames per second. + * + * <refsect2> + * <title>Example pipelines</title> + * |[ + * gst-launch ximagesrc ! video/x-raw-rgb,framerate=5/1 ! ffmpegcolorspace ! theoraenc ! oggmux ! filesink location=desktop.ogg + * ]| Encodes your X display to an Ogg theora video at 5 frames per second. + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "gstximagesrc.h" + +#include <string.h> +#include <stdlib.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include <gst/gst.h> +#include <gst/gst-i18n-plugin.h> + +#include "gst/glib-compat-private.h" + +GST_DEBUG_CATEGORY_STATIC (gst_debug_ximage_src); +#define GST_CAT_DEFAULT gst_debug_ximage_src + +static GstStaticPadTemplate t = +GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw-rgb, " + "framerate = (fraction) [ 0, MAX ], " + "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], " + "pixel-aspect-ratio = (fraction) [ 0, MAX ]")); + +enum +{ + PROP_0, + PROP_DISPLAY_NAME, + PROP_SCREEN_NUM, + PROP_SHOW_POINTER, + PROP_USE_DAMAGE, + PROP_STARTX, + PROP_STARTY, + PROP_ENDX, + PROP_ENDY, + PROP_REMOTE, + PROP_XID, + PROP_XNAME, +}; + +GST_BOILERPLATE (GstXImageSrc, gst_ximage_src, GstPushSrc, GST_TYPE_PUSH_SRC); + +static void gst_ximage_src_fixate (GstPad * pad, GstCaps * caps); +static void gst_ximage_src_clear_bufpool (GstXImageSrc * ximagesrc); + +/* Called when a buffer is returned from the pipeline */ +static void +gst_ximage_src_return_buf (GstXImageSrc * ximagesrc, + GstXImageSrcBuffer * ximage) +{ + /* If our geometry changed we can't reuse that image. */ + if ((ximage->width != ximagesrc->width) || + (ximage->height != ximagesrc->height)) { + GST_DEBUG_OBJECT (ximagesrc, + "destroy image %p as its size changed %dx%d vs current %dx%d", + ximage, ximage->width, ximage->height, + ximagesrc->width, ximagesrc->height); + g_mutex_lock (ximagesrc->x_lock); + gst_ximageutil_ximage_destroy (ximagesrc->xcontext, ximage); + g_mutex_unlock (ximagesrc->x_lock); + } else { + /* In that case we can reuse the image and add it to our image pool. */ + GST_LOG_OBJECT (ximagesrc, "recycling image %p in pool", ximage); + /* need to increment the refcount again to recycle */ + gst_buffer_ref (GST_BUFFER (ximage)); + g_mutex_lock (ximagesrc->pool_lock); + GST_BUFFER_FLAGS (GST_BUFFER (ximage)) = 0; /* clear out any flags from the previous use */ + ximagesrc->buffer_pool = g_slist_prepend (ximagesrc->buffer_pool, ximage); + g_mutex_unlock (ximagesrc->pool_lock); + } +} + +static Window +gst_ximage_src_find_window (GstXImageSrc * src, Window root, const char *name) +{ + Window *children; + Window window = 0, root_return, parent_return; + unsigned int nchildren; + char *tmpname; + int n, status; + + status = XFetchName (src->xcontext->disp, root, &tmpname); + if (status && !strcmp (name, tmpname)) + return root; + + status = + XQueryTree (src->xcontext->disp, root, &root_return, &parent_return, + &children, &nchildren); + if (!status || !children) + return (Window) 0; + + for (n = 0; n < nchildren; ++n) { + window = gst_ximage_src_find_window (src, children[n], name); + if (window != 0) + break; + } + + XFree (children); + return window; +} + +static gboolean +gst_ximage_src_open_display (GstXImageSrc * s, const gchar * name) +{ + g_return_val_if_fail (GST_IS_XIMAGE_SRC (s), FALSE); + + if (s->xcontext != NULL) + return TRUE; + + g_mutex_lock (s->x_lock); + s->xcontext = ximageutil_xcontext_get (GST_ELEMENT (s), name); + if (s->xcontext == NULL) { + g_mutex_unlock (s->x_lock); + GST_ELEMENT_ERROR (s, RESOURCE, OPEN_READ, + ("Could not open X display for reading"), + ("NULL returned from getting xcontext")); + return FALSE; + } + s->width = s->xcontext->width; + s->height = s->xcontext->height; + + s->xwindow = s->xcontext->root; + if (s->xid != 0 || s->xname) { + int status; + XWindowAttributes attrs; + Window window; + + if (s->xid != 0) { + status = XGetWindowAttributes (s->xcontext->disp, s->xid, &attrs); + if (status) { + GST_DEBUG_OBJECT (s, "Found window XID %" G_GUINT64_FORMAT, s->xid); + s->xwindow = s->xid; + goto window_found; + } else { + GST_WARNING_OBJECT (s, "Failed to get window %" G_GUINT64_FORMAT + " attributes", s->xid); + } + } + + if (s->xname) { + GST_DEBUG_OBJECT (s, "Looking for window %s", s->xname); + window = gst_ximage_src_find_window (s, s->xcontext->root, s->xname); + if (window != 0) { + GST_DEBUG_OBJECT (s, "Found window named %s, ", s->xname); + status = XGetWindowAttributes (s->xcontext->disp, window, &attrs); + if (status) { + s->xwindow = window; + goto window_found; + } else { + GST_WARNING_OBJECT (s, "Failed to get window attributes for " + "window named %s", s->xname); + } + } + } + + GST_INFO_OBJECT (s, "Using root window"); + goto use_root_window; + + window_found: + g_assert (s->xwindow != 0); + s->width = attrs.width; + s->height = attrs.height; + GST_INFO_OBJECT (s, "Using default window size of %dx%d", + s->width, s->height); + } +use_root_window: + +#ifdef HAVE_XFIXES + /* check if xfixes supported */ + { + int error_base; + + if (XFixesQueryExtension (s->xcontext->disp, &s->fixes_event_base, + &error_base)) { + s->have_xfixes = TRUE; + GST_DEBUG_OBJECT (s, "X Server supports XFixes"); + } else { + + GST_DEBUG_OBJECT (s, "X Server does not support XFixes"); + } + } + +#ifdef HAVE_XDAMAGE + /* check if xdamage is supported */ + { + int error_base; + long evmask = NoEventMask; + + s->have_xdamage = FALSE; + s->damage = None; + s->damage_copy_gc = None; + s->damage_region = None; + + if (XDamageQueryExtension (s->xcontext->disp, &s->damage_event_base, + &error_base)) { + s->damage = + XDamageCreate (s->xcontext->disp, s->xwindow, XDamageReportNonEmpty); + if (s->damage != None) { + s->damage_region = XFixesCreateRegion (s->xcontext->disp, NULL, 0); + if (s->damage_region != None) { + XGCValues values; + + GST_DEBUG_OBJECT (s, "Using XDamage extension"); + values.subwindow_mode = IncludeInferiors; + s->damage_copy_gc = XCreateGC (s->xcontext->disp, + s->xwindow, GCSubwindowMode, &values); + XSelectInput (s->xcontext->disp, s->xwindow, evmask); + + s->have_xdamage = TRUE; + } else { + XDamageDestroy (s->xcontext->disp, s->damage); + s->damage = None; + } + } else + GST_DEBUG_OBJECT (s, "Could not attach to XDamage"); + } else { + GST_DEBUG_OBJECT (s, "X Server does not have XDamage extension"); + } + } +#endif +#endif + + g_mutex_unlock (s->x_lock); + + if (s->xcontext == NULL) + return FALSE; + + return TRUE; +} + +static gboolean +gst_ximage_src_start (GstBaseSrc * basesrc) +{ + GstXImageSrc *s = GST_XIMAGE_SRC (basesrc); + + s->last_frame_no = -1; +#ifdef HAVE_XDAMAGE + if (s->last_ximage) + gst_buffer_unref (GST_BUFFER_CAST (s->last_ximage)); + s->last_ximage = NULL; +#endif + return gst_ximage_src_open_display (s, s->display_name); +} + +static gboolean +gst_ximage_src_stop (GstBaseSrc * basesrc) +{ + GstXImageSrc *src = GST_XIMAGE_SRC (basesrc); + +#ifdef HAVE_XDAMAGE + if (src->last_ximage) + gst_buffer_unref (GST_BUFFER_CAST (src->last_ximage)); + src->last_ximage = NULL; +#endif + + gst_ximage_src_clear_bufpool (src); + +#ifdef HAVE_XFIXES + if (src->cursor_image) + XFree (src->cursor_image); + src->cursor_image = NULL; +#endif + + if (src->xcontext) { + g_mutex_lock (src->x_lock); + +#ifdef HAVE_XDAMAGE + if (src->damage_copy_gc != None) { + XFreeGC (src->xcontext->disp, src->damage_copy_gc); + src->damage_copy_gc = None; + } + if (src->damage_region != None) { + XFixesDestroyRegion (src->xcontext->disp, src->damage_region); + src->damage_region = None; + } + if (src->damage != None) { + XDamageDestroy (src->xcontext->disp, src->damage); + src->damage = None; + } +#endif + + ximageutil_xcontext_clear (src->xcontext); + src->xcontext = NULL; + g_mutex_unlock (src->x_lock); + } + + return TRUE; +} + +static gboolean +gst_ximage_src_unlock (GstBaseSrc * basesrc) +{ + GstXImageSrc *src = GST_XIMAGE_SRC (basesrc); + + /* Awaken the create() func if it's waiting on the clock */ + GST_OBJECT_LOCK (src); + if (src->clock_id) { + GST_DEBUG_OBJECT (src, "Waking up waiting clock"); + gst_clock_id_unschedule (src->clock_id); + } + GST_OBJECT_UNLOCK (src); + + return TRUE; +} + +static gboolean +gst_ximage_src_recalc (GstXImageSrc * src) +{ + if (!src->xcontext) + return FALSE; + + /* Maybe later we can check the display hasn't changed size */ + /* We could use XQueryPointer to get only the current window. */ + return TRUE; +} + +#ifdef HAVE_XFIXES +static void +composite_pixel (GstXContext * xcontext, guchar * dest, guchar * src) +{ + guint8 r = src[2]; + guint8 g = src[1]; + guint8 b = src[0]; + guint8 a = src[3]; + guint8 dr, dg, db; + guint32 color; + gint r_shift, r_max, r_shift_out; + gint g_shift, g_max, g_shift_out; + gint b_shift, b_max, b_shift_out; + + switch (xcontext->bpp) { + case 8: + color = *dest; + break; + case 16: + color = GUINT16_FROM_LE (*(guint16 *) (dest)); + break; + case 32: + color = GUINT32_FROM_LE (*(guint32 *) (dest)); + break; + default: + /* Should not reach here */ + g_return_if_reached (); + } + + /* possible optimisation: + * move the code that finds shift and max in the _link function */ + for (r_shift = 0; !(xcontext->visual->red_mask & (1 << r_shift)); r_shift++); + for (g_shift = 0; !(xcontext->visual->green_mask & (1 << g_shift)); + g_shift++); + for (b_shift = 0; !(xcontext->visual->blue_mask & (1 << b_shift)); b_shift++); + + for (r_shift_out = 0; !(xcontext->visual->red_mask & (1 << r_shift_out)); + r_shift_out++); + for (g_shift_out = 0; !(xcontext->visual->green_mask & (1 << g_shift_out)); + g_shift_out++); + for (b_shift_out = 0; !(xcontext->visual->blue_mask & (1 << b_shift_out)); + b_shift_out++); + + + r_max = (xcontext->visual->red_mask >> r_shift); + b_max = (xcontext->visual->blue_mask >> b_shift); + g_max = (xcontext->visual->green_mask >> g_shift); + +#define RGBXXX_R(x) (((x)>>r_shift) & (r_max)) +#define RGBXXX_G(x) (((x)>>g_shift) & (g_max)) +#define RGBXXX_B(x) (((x)>>b_shift) & (b_max)) + + dr = (RGBXXX_R (color) * 255) / r_max; + dg = (RGBXXX_G (color) * 255) / g_max; + db = (RGBXXX_B (color) * 255) / b_max; + + dr = (r * a + (0xff - a) * dr) / 0xff; + dg = (g * a + (0xff - a) * dg) / 0xff; + db = (b * a + (0xff - a) * db) / 0xff; + + color = (((dr * r_max) / 255) << r_shift_out) + + (((dg * g_max) / 255) << g_shift_out) + + (((db * b_max) / 255) << b_shift_out); + + switch (xcontext->bpp) { + case 8: + *dest = color; + break; + case 16: + *(guint16 *) (dest) = color; + break; + case 32: + *(guint32 *) (dest) = color; + break; + default: + g_warning ("bpp %d not supported\n", xcontext->bpp); + } +} +#endif + +/* Retrieve an XImageSrcBuffer, preferably from our + * pool of existing images and populate it from the window */ +static GstXImageSrcBuffer * +gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc) +{ + GstXImageSrcBuffer *ximage = NULL; + + g_mutex_lock (ximagesrc->pool_lock); + while (ximagesrc->buffer_pool != NULL) { + ximage = ximagesrc->buffer_pool->data; + + if ((ximage->width != ximagesrc->width) || + (ximage->height != ximagesrc->height)) { + gst_ximage_buffer_free (ximage); + } + + ximagesrc->buffer_pool = g_slist_delete_link (ximagesrc->buffer_pool, + ximagesrc->buffer_pool); + } + g_mutex_unlock (ximagesrc->pool_lock); + + if (ximage == NULL) { + GstXContext *xcontext; + GstCaps *caps = NULL; + + GST_DEBUG_OBJECT (ximagesrc, "creating image (%dx%d)", + ximagesrc->width, ximagesrc->height); + + g_mutex_lock (ximagesrc->x_lock); + ximage = gst_ximageutil_ximage_new (ximagesrc->xcontext, + GST_ELEMENT (ximagesrc), ximagesrc->width, ximagesrc->height, + (BufferReturnFunc) (gst_ximage_src_return_buf)); + if (ximage == NULL) { + GST_ELEMENT_ERROR (ximagesrc, RESOURCE, WRITE, (NULL), + ("could not create a %dx%d ximage", ximagesrc->width, + ximagesrc->height)); + g_mutex_unlock (ximagesrc->x_lock); + return NULL; + } + + xcontext = ximagesrc->xcontext; + + + caps = gst_caps_new_simple ("video/x-raw-rgb", + "bpp", G_TYPE_INT, xcontext->bpp, + "depth", G_TYPE_INT, xcontext->depth, + "endianness", G_TYPE_INT, xcontext->endianness, + "red_mask", G_TYPE_INT, xcontext->r_mask_output, + "green_mask", G_TYPE_INT, xcontext->g_mask_output, + "blue_mask", G_TYPE_INT, xcontext->b_mask_output, + "width", G_TYPE_INT, ximagesrc->width, + "height", G_TYPE_INT, ximagesrc->height, + "framerate", GST_TYPE_FRACTION, ximagesrc->fps_n, ximagesrc->fps_d, + "pixel-aspect-ratio", GST_TYPE_FRACTION, + gst_value_get_fraction_numerator (xcontext->par), + gst_value_get_fraction_denominator (xcontext->par), NULL); + + gst_buffer_set_caps (GST_BUFFER (ximage), caps); + g_mutex_unlock (ximagesrc->x_lock); + + gst_caps_unref (caps); + } + + g_return_val_if_fail (GST_IS_XIMAGE_SRC (ximagesrc), NULL); +#ifdef HAVE_XDAMAGE + if (ximagesrc->have_xdamage && ximagesrc->use_damage && + ximagesrc->last_ximage != NULL) { + XEvent ev; + + /* have_frame is TRUE when either the entire screen has been + * grabbed or when the last image has been copied */ + gboolean have_frame = FALSE; + + GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XDamage"); + + do { + XNextEvent (ximagesrc->xcontext->disp, &ev); + + if (ev.type == ximagesrc->damage_event_base + XDamageNotify) { + XserverRegion parts; + XRectangle *rects; + int nrects; + + parts = XFixesCreateRegion (ximagesrc->xcontext->disp, 0, 0); + XDamageSubtract (ximagesrc->xcontext->disp, ximagesrc->damage, None, + parts); + /* Now copy out all of the damaged rectangles. */ + rects = XFixesFetchRegion (ximagesrc->xcontext->disp, parts, &nrects); + if (rects != NULL) { + int i; + + if (!have_frame) { + GST_LOG_OBJECT (ximagesrc, + "Copying from last frame ximage->size: %d", + GST_BUFFER_SIZE (GST_BUFFER (ximage))); + memcpy (GST_BUFFER_DATA (GST_BUFFER (ximage)), + GST_BUFFER_DATA (GST_BUFFER (ximagesrc->last_ximage)), + GST_BUFFER_SIZE (GST_BUFFER (ximage))); + have_frame = TRUE; + } + for (i = 0; i < nrects; i++) { + GST_LOG_OBJECT (ximagesrc, + "Damaged sub-region @ %d,%d size %dx%d reported", + rects[i].x, rects[i].y, rects[i].width, rects[i].height); + + /* if we only want a small area, clip this damage region to + * area we want */ + if (ximagesrc->endx > ximagesrc->startx && + ximagesrc->endy > ximagesrc->starty) { + /* see if damage area intersects */ + if (rects[i].x + rects[i].width - 1 < ximagesrc->startx || + rects[i].x > ximagesrc->endx) { + /* trivial reject */ + } else if (rects[i].y + rects[i].height - 1 < ximagesrc->starty || + rects[i].y > ximagesrc->endy) { + /* trivial reject */ + } else { + /* find intersect region */ + int startx, starty, width, height; + + startx = (rects[i].x < ximagesrc->startx) ? ximagesrc->startx : + rects[i].x; + starty = (rects[i].y < ximagesrc->starty) ? ximagesrc->starty : + rects[i].y; + width = (rects[i].x + rects[i].width - 1 < ximagesrc->endx) ? + rects[i].x + rects[i].width - startx : + ximagesrc->endx - startx + 1; + height = (rects[i].y + rects[i].height - 1 < ximagesrc->endy) ? + rects[i].y + rects[i].height - starty : ximagesrc->endy - + starty + 1; + + GST_LOG_OBJECT (ximagesrc, + "Retrieving damaged sub-region @ %d,%d size %dx%d as intersect region", + startx, starty, width, height); + XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, + startx, starty, width, height, AllPlanes, ZPixmap, + ximage->ximage, startx - ximagesrc->startx, + starty - ximagesrc->starty); + } + } else { + + GST_LOG_OBJECT (ximagesrc, + "Retrieving damaged sub-region @ %d,%d size %dx%d", + rects[i].x, rects[i].y, rects[i].width, rects[i].height); + + XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, + rects[i].x, rects[i].y, + rects[i].width, rects[i].height, + AllPlanes, ZPixmap, ximage->ximage, rects[i].x, rects[i].y); + } + } + free (rects); + } + } + } while (XPending (ximagesrc->xcontext->disp)); + if (!have_frame) { + GST_LOG_OBJECT (ximagesrc, + "Copying from last frame ximage->size: %d", + GST_BUFFER_SIZE (GST_BUFFER (ximage))); + memcpy (GST_BUFFER_DATA (GST_BUFFER (ximage)), + GST_BUFFER_DATA (GST_BUFFER (ximagesrc->last_ximage)), + GST_BUFFER_SIZE (GST_BUFFER (ximage))); + } +#ifdef HAVE_XFIXES + /* re-get area where last mouse pointer was but only if in our clipping + * bounds */ + if (ximagesrc->cursor_image) { + gint x, y, width, height; + + x = ximagesrc->cursor_image->x - ximagesrc->cursor_image->xhot; + y = ximagesrc->cursor_image->y - ximagesrc->cursor_image->yhot; + width = ximagesrc->cursor_image->width; + height = ximagesrc->cursor_image->height; + + /* bounds checking */ + if (x < 0) + x = 0; + if (y < 0) + y = 0; + if (x + width > ximagesrc->xcontext->width) + width = ximagesrc->xcontext->width - x; + if (y + height > ximagesrc->xcontext->height) + height = ximagesrc->xcontext->height - y; + g_assert (x >= 0); + g_assert (y >= 0); + GST_DEBUG_OBJECT (ximagesrc, + "Cursor was at (%d,%d) width: %d, height: %d and our range is: (%d,%d) - (%d,%d)", + x, y, width, height, ximagesrc->startx, ximagesrc->starty, + ximagesrc->endx, ximagesrc->endy); + /* only get where cursor last was, if it is in our range */ + if (ximagesrc->endx > ximagesrc->startx && + ximagesrc->endy > ximagesrc->starty) { + /* check bounds */ + if (x + width < ximagesrc->startx || x > ximagesrc->endx) { + /* trivial reject */ + } else if (y + height < ximagesrc->starty || y > ximagesrc->endy) { + /* trivial reject */ + } else { + /* find intersect region */ + int startx, starty, iwidth, iheight; + + startx = (x < ximagesrc->startx) ? ximagesrc->startx : x; + starty = (y < ximagesrc->starty) ? ximagesrc->starty : y; + iwidth = (x + width < ximagesrc->endx) ? + x + width - startx : ximagesrc->endx - startx; + iheight = (y + height < ximagesrc->endy) ? + y + height - starty : ximagesrc->endy - starty; + GST_DEBUG_OBJECT (ximagesrc, "Removing cursor from %d,%d", x, y); + XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, + startx, starty, iwidth, iheight, AllPlanes, ZPixmap, + ximage->ximage, startx - ximagesrc->startx, + starty - ximagesrc->starty); + } + } else { + + GST_DEBUG_OBJECT (ximagesrc, "Removing cursor from %d,%d", x, y); + XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, + x, y, width, height, AllPlanes, ZPixmap, ximage->ximage, x, y); + } + } +#endif + + + } else { +#endif + +#ifdef HAVE_XSHM + if (ximagesrc->xcontext->use_xshm) { + GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XShm"); + XShmGetImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, + ximage->ximage, ximagesrc->startx, ximagesrc->starty, AllPlanes); + + } else +#endif /* HAVE_XSHM */ + { + GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XGetImage"); + if (ximagesrc->remote) { + XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, + ximagesrc->startx, ximagesrc->starty, ximagesrc->width, + ximagesrc->height, AllPlanes, ZPixmap, ximage->ximage, 0, 0); + } else { + ximage->ximage = + XGetImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, + ximagesrc->startx, ximagesrc->starty, ximagesrc->width, + ximagesrc->height, AllPlanes, ZPixmap); + } + } +#ifdef HAVE_XDAMAGE + } +#endif + +#ifdef HAVE_XFIXES + if (ximagesrc->show_pointer && ximagesrc->have_xfixes) { + + GST_DEBUG_OBJECT (ximagesrc, "Using XFixes to draw cursor"); + /* get cursor */ + if (ximagesrc->cursor_image) + XFree (ximagesrc->cursor_image); + ximagesrc->cursor_image = XFixesGetCursorImage (ximagesrc->xcontext->disp); + if (ximagesrc->cursor_image != NULL) { + int cx, cy, i, j, count; + int startx, starty, iwidth, iheight; + gboolean cursor_in_image = TRUE; + + cx = ximagesrc->cursor_image->x - ximagesrc->cursor_image->xhot; + if (cx < 0) + cx = 0; + cy = ximagesrc->cursor_image->y - ximagesrc->cursor_image->yhot; + if (cy < 0) + cy = 0; + count = ximagesrc->cursor_image->width * ximagesrc->cursor_image->height; + + /* only get where cursor last was, if it is in our range */ + if (ximagesrc->endx > ximagesrc->startx && + ximagesrc->endy > ximagesrc->starty) { + /* check bounds */ + if (cx + ximagesrc->cursor_image->width < ximagesrc->startx || + cx > ximagesrc->endx) { + /* trivial reject */ + cursor_in_image = FALSE; + } else if (cy + ximagesrc->cursor_image->height < ximagesrc->starty || + cy > ximagesrc->endy) { + /* trivial reject */ + cursor_in_image = FALSE; + } else { + /* find intersect region */ + + startx = (cx < ximagesrc->startx) ? ximagesrc->startx : cx; + starty = (cy < ximagesrc->starty) ? ximagesrc->starty : cy; + iwidth = (cx + ximagesrc->cursor_image->width < ximagesrc->endx) ? + cx + ximagesrc->cursor_image->width - startx : + ximagesrc->endx - startx; + iheight = (cy + ximagesrc->cursor_image->height < ximagesrc->endy) ? + cy + ximagesrc->cursor_image->height - starty : + ximagesrc->endy - starty; + } + } else { + startx = cx; + starty = cy; + iwidth = ximagesrc->cursor_image->width; + iheight = ximagesrc->cursor_image->height; + } + + if (cursor_in_image) { + GST_DEBUG_OBJECT (ximagesrc, "Cursor is in image so trying to draw it"); + for (i = 0; i < count; i++) + ximagesrc->cursor_image->pixels[i] = + GUINT_TO_LE (ximagesrc->cursor_image->pixels[i]); + /* copy those pixels across */ + for (j = starty; + j < starty + iheight && j < ximagesrc->starty + ximagesrc->height; + j++) { + for (i = startx; + i < startx + iwidth && i < ximagesrc->startx + ximagesrc->width; + i++) { + guint8 *src, *dest; + + src = + (guint8 *) & (ximagesrc->cursor_image->pixels[((j - + cy) * ximagesrc->cursor_image->width + (i - cx))]); + dest = + (guint8 *) & (ximage->ximage->data[((j - + ximagesrc->starty) * ximagesrc->width + (i - + ximagesrc->startx)) * (ximagesrc->xcontext->bpp / + 8)]); + + composite_pixel (ximagesrc->xcontext, (guint8 *) dest, + (guint8 *) src); + } + } + } + } + } +#endif +#ifdef HAVE_XDAMAGE + if (ximagesrc->have_xdamage && ximagesrc->use_damage) { + /* need to ref ximage to put in last_ximage */ + gst_buffer_ref (GST_BUFFER (ximage)); + if (ximagesrc->last_ximage) { + gst_buffer_unref (GST_BUFFER (ximagesrc->last_ximage)); + } + ximagesrc->last_ximage = ximage; + GST_LOG_OBJECT (ximagesrc, "reffing current buffer for last_ximage"); + } +#endif + return ximage; +} + +static GstFlowReturn +gst_ximage_src_create (GstPushSrc * bs, GstBuffer ** buf) +{ + GstXImageSrc *s = GST_XIMAGE_SRC (bs); + GstXImageSrcBuffer *image; + GstClockTime base_time; + GstClockTime next_capture_ts; + GstClockTime dur; + gint64 next_frame_no; + + if (!gst_ximage_src_recalc (s)) { + GST_ELEMENT_ERROR (s, RESOURCE, FAILED, + (_("Changing resolution at runtime is not yet supported.")), (NULL)); + return GST_FLOW_ERROR; + } + + if (s->fps_n <= 0 || s->fps_d <= 0) + return GST_FLOW_NOT_NEGOTIATED; /* FPS must be > 0 */ + + /* Now, we might need to wait for the next multiple of the fps + * before capturing */ + + GST_OBJECT_LOCK (s); + if (GST_ELEMENT_CLOCK (s) == NULL) { + GST_OBJECT_UNLOCK (s); + GST_ELEMENT_ERROR (s, RESOURCE, FAILED, + (_("Cannot operate without a clock")), (NULL)); + return GST_FLOW_ERROR; + } + + base_time = GST_ELEMENT_CAST (s)->base_time; + next_capture_ts = gst_clock_get_time (GST_ELEMENT_CLOCK (s)); + next_capture_ts -= base_time; + + /* Figure out which 'frame number' position we're at, based on the cur time + * and frame rate */ + next_frame_no = gst_util_uint64_scale (next_capture_ts, + s->fps_n, GST_SECOND * s->fps_d); + if (next_frame_no == s->last_frame_no) { + GstClockID id; + GstClockReturn ret; + + /* Need to wait for the next frame */ + next_frame_no += 1; + + /* Figure out what the next frame time is */ + next_capture_ts = gst_util_uint64_scale (next_frame_no, + s->fps_d * GST_SECOND, s->fps_n); + + id = gst_clock_new_single_shot_id (GST_ELEMENT_CLOCK (s), + next_capture_ts + base_time); + s->clock_id = id; + + /* release the object lock while waiting */ + GST_OBJECT_UNLOCK (s); + + GST_DEBUG_OBJECT (s, "Waiting for next frame time %" G_GUINT64_FORMAT, + next_capture_ts); + ret = gst_clock_id_wait (id, NULL); + GST_OBJECT_LOCK (s); + + gst_clock_id_unref (id); + s->clock_id = NULL; + if (ret == GST_CLOCK_UNSCHEDULED) { + /* Got woken up by the unlock function */ + GST_OBJECT_UNLOCK (s); + return GST_FLOW_WRONG_STATE; + } + /* Duration is a complete 1/fps frame duration */ + dur = gst_util_uint64_scale_int (GST_SECOND, s->fps_d, s->fps_n); + } else { + GstClockTime next_frame_ts; + + GST_DEBUG_OBJECT (s, "No need to wait for next frame time %" + G_GUINT64_FORMAT " next frame = %" G_GINT64_FORMAT " prev = %" + G_GINT64_FORMAT, next_capture_ts, next_frame_no, s->last_frame_no); + next_frame_ts = gst_util_uint64_scale (next_frame_no + 1, + s->fps_d * GST_SECOND, s->fps_n); + /* Frame duration is from now until the next expected capture time */ + dur = next_frame_ts - next_capture_ts; + } + s->last_frame_no = next_frame_no; + GST_OBJECT_UNLOCK (s); + + image = gst_ximage_src_ximage_get (s); + if (!image) + return GST_FLOW_ERROR; + + *buf = GST_BUFFER (image); + GST_BUFFER_TIMESTAMP (*buf) = next_capture_ts; + GST_BUFFER_DURATION (*buf) = dur; + + return GST_FLOW_OK; +} + +static void +gst_ximage_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstXImageSrc *src = GST_XIMAGE_SRC (object); + + switch (prop_id) { + case PROP_DISPLAY_NAME: + + g_free (src->display_name); + src->display_name = g_strdup (g_value_get_string (value)); + break; + case PROP_SCREEN_NUM: + src->screen_num = g_value_get_uint (value); + break; + case PROP_SHOW_POINTER: + src->show_pointer = g_value_get_boolean (value); + break; + case PROP_USE_DAMAGE: + src->use_damage = g_value_get_boolean (value); + break; + case PROP_STARTX: + src->startx = g_value_get_uint (value); + break; + case PROP_STARTY: + src->starty = g_value_get_uint (value); + break; + case PROP_ENDX: + src->endx = g_value_get_uint (value); + break; + case PROP_ENDY: + src->endy = g_value_get_uint (value); + break; + case PROP_REMOTE: + src->remote = g_value_get_boolean (value); + break; + case PROP_XID: + if (src->xcontext != NULL) { + g_warning ("ximagesrc window ID must be set before opening display"); + break; + } + src->xid = g_value_get_uint64 (value); + break; + case PROP_XNAME: + if (src->xcontext != NULL) { + g_warning ("ximagesrc window name must be set before opening display"); + break; + } + g_free (src->xname); + src->xname = g_strdup (g_value_get_string (value)); + break; + default: + break; + } +} + +static void +gst_ximage_src_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstXImageSrc *src = GST_XIMAGE_SRC (object); + + switch (prop_id) { + case PROP_DISPLAY_NAME: + if (src->xcontext) + g_value_set_string (value, DisplayString (src->xcontext->disp)); + else + g_value_set_string (value, src->display_name); + + break; + case PROP_SCREEN_NUM: + g_value_set_uint (value, src->screen_num); + break; + case PROP_SHOW_POINTER: + g_value_set_boolean (value, src->show_pointer); + break; + case PROP_USE_DAMAGE: + g_value_set_boolean (value, src->use_damage); + break; + case PROP_STARTX: + g_value_set_uint (value, src->startx); + break; + case PROP_STARTY: + g_value_set_uint (value, src->starty); + break; + case PROP_ENDX: + g_value_set_uint (value, src->endx); + break; + case PROP_ENDY: + g_value_set_uint (value, src->endy); + break; + case PROP_REMOTE: + g_value_set_boolean (value, src->remote); + break; + case PROP_XID: + g_value_set_uint64 (value, src->xid); + break; + case PROP_XNAME: + g_value_set_string (value, src->xname); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_ximage_src_clear_bufpool (GstXImageSrc * ximagesrc) +{ + g_mutex_lock (ximagesrc->pool_lock); + while (ximagesrc->buffer_pool != NULL) { + GstXImageSrcBuffer *ximage = ximagesrc->buffer_pool->data; + + gst_ximage_buffer_free (ximage); + + ximagesrc->buffer_pool = g_slist_delete_link (ximagesrc->buffer_pool, + ximagesrc->buffer_pool); + } + g_mutex_unlock (ximagesrc->pool_lock); +} + +static void +gst_ximage_src_base_init (gpointer g_class) +{ + GstElementClass *ec = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details_simple (ec, "Ximage video source", + "Source/Video", + "Creates a screenshot video stream", + "Lutz Mueller <lutz@users.sourceforge.net>, " + "Jan Schmidt <thaytan@mad.scientist.com>, " + "Zaheer Merali <zaheerabbas at merali dot org>"); + gst_element_class_add_static_pad_template (ec, &t); +} + +static void +gst_ximage_src_dispose (GObject * object) +{ + /* Drop references in the buffer_pool */ + gst_ximage_src_clear_bufpool (GST_XIMAGE_SRC (object)); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_ximage_src_finalize (GObject * object) +{ + GstXImageSrc *src = GST_XIMAGE_SRC (object); + + if (src->xcontext) + ximageutil_xcontext_clear (src->xcontext); + + g_free (src->xname); + g_mutex_free (src->pool_lock); + g_mutex_free (src->x_lock); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static GstCaps * +gst_ximage_src_get_caps (GstBaseSrc * bs) +{ + GstXImageSrc *s = GST_XIMAGE_SRC (bs); + GstXContext *xcontext; + gint width, height; + + if ((!s->xcontext) && (!gst_ximage_src_open_display (s, s->display_name))) + return + gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC + (s)->srcpad)); + + if (!gst_ximage_src_recalc (s)) + return + gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC + (s)->srcpad)); + + xcontext = s->xcontext; + width = s->xcontext->width; + height = s->xcontext->height; + if (s->xwindow != 0) { + XWindowAttributes attrs; + int status = XGetWindowAttributes (s->xcontext->disp, s->xwindow, &attrs); + if (status) { + width = attrs.width; + height = attrs.height; + } + } + + /* property comments say 0 means right/bottom, means we can't capture + the top left pixel alone */ + if (s->endx == 0) + s->endx = width - 1; + if (s->endy == 0) + s->endy = height - 1; + + if (s->endx >= s->startx && s->endy >= s->starty) { + /* this means user has put in values */ + if (s->startx < xcontext->width && s->endx < xcontext->width && + s->starty < xcontext->height && s->endy < xcontext->height && + s->startx >= 0 && s->starty >= 0) { + /* values are fine */ + s->width = width = s->endx - s->startx + 1; + s->height = height = s->endy - s->starty + 1; + } else { + GST_WARNING + ("User put in co-ordinates overshooting the X resolution, setting to full screen"); + s->startx = 0; + s->starty = 0; + s->endx = width - 1; + s->endy = height - 1; + } + } else { + GST_WARNING ("User put in bogus co-ordinates, setting to full screen"); + s->startx = 0; + s->starty = 0; + s->endx = width - 1; + s->endy = height - 1; + } + GST_DEBUG ("width = %d, height=%d", width, height); + return gst_caps_new_simple ("video/x-raw-rgb", + "bpp", G_TYPE_INT, xcontext->bpp, + "depth", G_TYPE_INT, xcontext->depth, + "endianness", G_TYPE_INT, xcontext->endianness, + "red_mask", G_TYPE_INT, xcontext->r_mask_output, + "green_mask", G_TYPE_INT, xcontext->g_mask_output, + "blue_mask", G_TYPE_INT, xcontext->b_mask_output, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + "framerate", GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1, + "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1, + NULL); +} + +static gboolean +gst_ximage_src_set_caps (GstBaseSrc * bs, GstCaps * caps) +{ + GstXImageSrc *s = GST_XIMAGE_SRC (bs); + GstStructure *structure; + const GValue *new_fps; + + /* If not yet opened, disallow setcaps until later */ + if (!s->xcontext) + return FALSE; + + /* The only thing that can change is the framerate downstream wants */ + structure = gst_caps_get_structure (caps, 0); + new_fps = gst_structure_get_value (structure, "framerate"); + if (!new_fps) + return FALSE; + + /* Store this FPS for use when generating buffers */ + s->fps_n = gst_value_get_fraction_numerator (new_fps); + s->fps_d = gst_value_get_fraction_denominator (new_fps); + + GST_DEBUG_OBJECT (s, "peer wants %d/%d fps", s->fps_n, s->fps_d); + + return TRUE; +} + +static void +gst_ximage_src_fixate (GstPad * pad, GstCaps * caps) +{ + gint i; + GstStructure *structure; + + for (i = 0; i < gst_caps_get_size (caps); ++i) { + structure = gst_caps_get_structure (caps, i); + + gst_structure_fixate_field_nearest_fraction (structure, "framerate", 25, 1); + } +} + +static void +gst_ximage_src_class_init (GstXImageSrcClass * klass) +{ + GObjectClass *gc = G_OBJECT_CLASS (klass); + GstBaseSrcClass *bc = GST_BASE_SRC_CLASS (klass); + GstPushSrcClass *push_class = GST_PUSH_SRC_CLASS (klass); + + gc->set_property = gst_ximage_src_set_property; + gc->get_property = gst_ximage_src_get_property; + gc->dispose = gst_ximage_src_dispose; + gc->finalize = gst_ximage_src_finalize; + + g_object_class_install_property (gc, PROP_DISPLAY_NAME, + g_param_spec_string ("display-name", "Display", "X Display Name", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gc, PROP_SCREEN_NUM, + g_param_spec_uint ("screen-num", "Screen number", "X Screen Number", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gc, PROP_SHOW_POINTER, + g_param_spec_boolean ("show-pointer", "Show Mouse Pointer", + "Show mouse pointer (if XFixes extension enabled)", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstXImageSrc:use-damage + * + * Use XDamage (if the XDamage extension is enabled) + * + * Since: 0.10.4 + **/ + g_object_class_install_property (gc, PROP_USE_DAMAGE, + g_param_spec_boolean ("use-damage", "Use XDamage", + "Use XDamage (if XDamage extension enabled)", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstXImageSrc:startx + * + * X coordinate of top left corner of area to be recorded + * (0 for top left of screen) + * + * Since: 0.10.4 + **/ + g_object_class_install_property (gc, PROP_STARTX, + g_param_spec_uint ("startx", "Start X co-ordinate", + "X coordinate of top left corner of area to be recorded (0 for top left of screen)", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstXImageSrc:starty + * + * Y coordinate of top left corner of area to be recorded + * (0 for top left of screen) + * + * Since: 0.10.4 + **/ + g_object_class_install_property (gc, PROP_STARTY, + g_param_spec_uint ("starty", "Start Y co-ordinate", + "Y coordinate of top left corner of area to be recorded (0 for top left of screen)", + 0, G_MAXINT, 0, G_PARAM_READWRITE)); + /** + * GstXImageSrc:endx + * + * X coordinate of bottom right corner of area to be recorded + * (0 for bottom right of screen) + * + * Since: 0.10.4 + **/ + g_object_class_install_property (gc, PROP_ENDX, + g_param_spec_uint ("endx", "End X", + "X coordinate of bottom right corner of area to be recorded (0 for bottom right of screen)", + 0, G_MAXINT, 0, G_PARAM_READWRITE)); + /** + * GstXImageSrc:endy + * + * Y coordinate of bottom right corner of area to be recorded + * (0 for bottom right of screen) + * + * Since: 0.10.4 + **/ + g_object_class_install_property (gc, PROP_ENDY, + g_param_spec_uint ("endy", "End Y", + "Y coordinate of bottom right corner of area to be recorded (0 for bottom right of screen)", + 0, G_MAXINT, 0, G_PARAM_READWRITE)); + + /** + * GstXImageSrc:remote + * + * Whether the X display is remote. The element will try to use alternate calls + * known to work better with remote displays. + * + * Since: 0.10.26 + **/ + g_object_class_install_property (gc, PROP_REMOTE, + g_param_spec_boolean ("remote", "Remote dispay", + "Whether the display is remote", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXImageSrc:xid + * + * The XID of the window to capture. 0 for the root window (default). + * + * Since: 0.10.31 + **/ + g_object_class_install_property (gc, PROP_XID, + g_param_spec_uint64 ("xid", "Window XID", + "Window XID to capture from", 0, G_MAXUINT64, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstXImageSrc:xname + * + * The name of the window to capture, if any. + * + * Since: 0.10.31 + **/ + g_object_class_install_property (gc, PROP_XNAME, + g_param_spec_string ("xname", "Window name", + "Window name to capture from", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + parent_class = g_type_class_peek_parent (klass); + + push_class->create = gst_ximage_src_create; + bc->get_caps = gst_ximage_src_get_caps; + bc->set_caps = gst_ximage_src_set_caps; + bc->start = gst_ximage_src_start; + bc->stop = gst_ximage_src_stop; + bc->unlock = gst_ximage_src_unlock; +} + +static void +gst_ximage_src_init (GstXImageSrc * ximagesrc, GstXImageSrcClass * klass) +{ + gst_base_src_set_format (GST_BASE_SRC (ximagesrc), GST_FORMAT_TIME); + gst_base_src_set_live (GST_BASE_SRC (ximagesrc), TRUE); + gst_pad_set_fixatecaps_function (GST_BASE_SRC_PAD (ximagesrc), + gst_ximage_src_fixate); + + ximagesrc->pool_lock = g_mutex_new (); + ximagesrc->x_lock = g_mutex_new (); + ximagesrc->show_pointer = TRUE; + ximagesrc->use_damage = TRUE; + ximagesrc->startx = 0; + ximagesrc->starty = 0; + ximagesrc->endx = 0; + ximagesrc->endy = 0; + ximagesrc->remote = FALSE; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + gboolean ret; + + GST_DEBUG_CATEGORY_INIT (gst_debug_ximage_src, "ximagesrc", 0, + "ximagesrc element debug"); + + ret = gst_element_register (plugin, "ximagesrc", GST_RANK_NONE, + GST_TYPE_XIMAGE_SRC); + + return ret; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "ximagesrc", + "X11 video input plugin using standard Xlib calls", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); diff --git a/sys/ximage/gstximagesrc.h b/sys/ximage/gstximagesrc.h new file mode 100644 index 0000000..e58513c --- /dev/null +++ b/sys/ximage/gstximagesrc.h @@ -0,0 +1,113 @@ +/* screenshotsrc: Screenshot plugin for GStreamer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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_XIMAGE_SRC_H__ +#define __GST_XIMAGE_SRC_H__ + +#include <gst/gst.h> +#include <gst/base/gstpushsrc.h> +#include "ximageutil.h" + +#ifdef HAVE_XFIXES +#include <X11/extensions/Xfixes.h> +#endif +#ifdef HAVE_XDAMAGE +#include <X11/extensions/Xdamage.h> +#endif + +G_BEGIN_DECLS + +#define GST_TYPE_XIMAGE_SRC (gst_ximage_src_get_type()) +#define GST_XIMAGE_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XIMAGE_SRC,GstXImageSrc)) +#define GST_XIMAGE_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XIMAGE_SRC,GstXImageSrc)) +#define GST_IS_XIMAGE_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XIMAGE_SRC)) +#define GST_IS_XIMAGE_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XIMAGE_SRC)) + +typedef struct _GstXImageSrc GstXImageSrc; +typedef struct _GstXImageSrcClass GstXImageSrcClass; + +GType gst_ximage_src_get_type (void) G_GNUC_CONST; + +struct _GstXImageSrc +{ + GstPushSrc parent; + + /* Information on display */ + GstXContext *xcontext; + gint width; + gint height; + + Window xwindow; + gchar *display_name; + guint screen_num; + + /* Window selection */ + guint64 xid; + gchar *xname; + + /* Desired output framerate */ + gint fps_n; + gint fps_d; + + /* for framerate sync */ + GstClockID clock_id; + gint64 last_frame_no; + + /* Protect X Windows calls */ + GMutex *x_lock; + + /* Gathered pool of emitted buffers */ + GMutex *pool_lock; + GSList *buffer_pool; + + /* XFixes and XDamage support */ + gboolean have_xfixes; + gboolean have_xdamage; + gboolean show_pointer; + gboolean use_damage; + + /* co-ordinates for start and end */ + guint startx; + guint starty; + guint endx; + guint endy; + + /* whether to use remote friendly calls */ + gboolean remote; + +#ifdef HAVE_XFIXES + int fixes_event_base; + XFixesCursorImage *cursor_image; +#endif +#ifdef HAVE_XDAMAGE + Damage damage; + int damage_event_base; + XserverRegion damage_region; + GC damage_copy_gc; + GstXImageSrcBuffer *last_ximage; +#endif +}; + +struct _GstXImageSrcClass +{ + GstPushSrcClass parent_class; +}; + +G_END_DECLS + +#endif /* __GST_XIMAGE_SRC_H__ */ diff --git a/sys/ximage/ximageutil.c b/sys/ximage/ximageutil.c new file mode 100644 index 0000000..2fac09a --- /dev/null +++ b/sys/ximage/ximageutil.c @@ -0,0 +1,501 @@ +/* GStreamer + * Copyright (C) <2005> Luca Ognibene <luogni@tin.it> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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 "ximageutil.h" + +#ifdef HAVE_XSHM +static gboolean error_caught = FALSE; + +static int +ximageutil_handle_xerror (Display * display, XErrorEvent * xevent) +{ + char error_msg[1024]; + + XGetErrorText (display, xevent->error_code, error_msg, 1024); + GST_DEBUG ("ximageutil failed to use XShm calls. error: %s", error_msg); + error_caught = TRUE; + return 0; +} + +/* This function checks that it is actually really possible to create an image + using XShm */ +gboolean +ximageutil_check_xshm_calls (GstXContext * xcontext) +{ + XImage *ximage; + XShmSegmentInfo SHMInfo; + size_t size; + int (*handler) (Display *, XErrorEvent *); + gboolean result = FALSE; + gboolean did_attach = FALSE; + + g_return_val_if_fail (xcontext != NULL, FALSE); + + /* Sync to ensure any older errors are already processed */ + XSync (xcontext->disp, FALSE); + + /* Set defaults so we don't free these later unnecessarily */ + SHMInfo.shmaddr = ((void *) -1); + SHMInfo.shmid = -1; + + /* Setting an error handler to catch failure */ + error_caught = FALSE; + handler = XSetErrorHandler (ximageutil_handle_xerror); + + /* Trying to create a 1x1 ximage */ + GST_DEBUG ("XShmCreateImage of 1x1"); + + ximage = XShmCreateImage (xcontext->disp, xcontext->visual, + xcontext->depth, ZPixmap, NULL, &SHMInfo, 1, 1); + + /* Might cause an error, sync to ensure it is noticed */ + XSync (xcontext->disp, FALSE); + if (!ximage || error_caught) { + GST_WARNING ("could not XShmCreateImage a 1x1 image"); + goto beach; + } + size = ximage->height * ximage->bytes_per_line; + + SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); + if (SHMInfo.shmid == -1) { + GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", + size); + goto beach; + } + + SHMInfo.shmaddr = shmat (SHMInfo.shmid, 0, 0); + if (SHMInfo.shmaddr == ((void *) -1)) { + GST_WARNING ("Failed to shmat: %s", g_strerror (errno)); + goto beach; + } + + /* Delete the SHM segment. It will actually go away automatically + * when we detach now */ + shmctl (SHMInfo.shmid, IPC_RMID, 0); + + ximage->data = SHMInfo.shmaddr; + SHMInfo.readOnly = FALSE; + + if (XShmAttach (xcontext->disp, &SHMInfo) == 0) { + GST_WARNING ("Failed to XShmAttach"); + goto beach; + } + + /* Sync to ensure we see any errors we caused */ + XSync (xcontext->disp, FALSE); + + if (!error_caught) { + did_attach = TRUE; + /* store whether we succeeded in result */ + result = TRUE; + } +beach: + /* Sync to ensure we swallow any errors we caused and reset error_caught */ + XSync (xcontext->disp, FALSE); + error_caught = FALSE; + XSetErrorHandler (handler); + + if (did_attach) { + XShmDetach (xcontext->disp, &SHMInfo); + XSync (xcontext->disp, FALSE); + } + if (SHMInfo.shmaddr != ((void *) -1)) + shmdt (SHMInfo.shmaddr); + if (ximage) + XDestroyImage (ximage); + return result; +} +#endif /* HAVE_XSHM */ + +/* This function gets the X Display and global info about it. Everything is + stored in our object and will be cleaned when the object is disposed. Note + here that caps for supported format are generated without any window or + image creation */ +GstXContext * +ximageutil_xcontext_get (GstElement * parent, const gchar * display_name) +{ + GstXContext *xcontext = NULL; + XPixmapFormatValues *px_formats = NULL; + gint nb_formats = 0, i; + + xcontext = g_new0 (GstXContext, 1); + + xcontext->disp = XOpenDisplay (display_name); + GST_DEBUG_OBJECT (parent, "opened display %p", xcontext->disp); + if (!xcontext->disp) { + g_free (xcontext); + return NULL; + } + xcontext->screen = DefaultScreenOfDisplay (xcontext->disp); + xcontext->screen_num = DefaultScreen (xcontext->disp); + xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num); + xcontext->root = DefaultRootWindow (xcontext->disp); + xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num); + xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num); + xcontext->depth = DefaultDepthOfScreen (xcontext->screen); + + xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num); + xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num); + + xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num); + xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num); + + xcontext->caps = NULL; + + GST_DEBUG_OBJECT (parent, "X reports %dx%d pixels and %d mm x %d mm", + xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm); + ximageutil_calculate_pixel_aspect_ratio (xcontext); + + /* We get supported pixmap formats at supported depth */ + px_formats = XListPixmapFormats (xcontext->disp, &nb_formats); + + if (!px_formats) { + XCloseDisplay (xcontext->disp); + g_free (xcontext); + return NULL; + } + + /* We get bpp value corresponding to our running depth */ + for (i = 0; i < nb_formats; i++) { + if (px_formats[i].depth == xcontext->depth) + xcontext->bpp = px_formats[i].bits_per_pixel; + } + + XFree (px_formats); + + xcontext->endianness = + (ImageByteOrder (xcontext->disp) == + LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN; + +#ifdef HAVE_XSHM + /* Search for XShm extension support */ + if (XShmQueryExtension (xcontext->disp) && + ximageutil_check_xshm_calls (xcontext)) { + xcontext->use_xshm = TRUE; + GST_DEBUG ("ximageutil is using XShm extension"); + } else { + xcontext->use_xshm = FALSE; + GST_DEBUG ("ximageutil is not using XShm extension"); + } +#endif /* HAVE_XSHM */ + + /* our caps system handles 24/32bpp RGB as big-endian. */ + if ((xcontext->bpp == 24 || xcontext->bpp == 32) && + xcontext->endianness == G_LITTLE_ENDIAN) { + xcontext->endianness = G_BIG_ENDIAN; + xcontext->r_mask_output = GUINT32_TO_BE (xcontext->visual->red_mask); + xcontext->g_mask_output = GUINT32_TO_BE (xcontext->visual->green_mask); + xcontext->b_mask_output = GUINT32_TO_BE (xcontext->visual->blue_mask); + if (xcontext->bpp == 24) { + xcontext->r_mask_output >>= 8; + xcontext->g_mask_output >>= 8; + xcontext->b_mask_output >>= 8; + } + } else { + xcontext->r_mask_output = xcontext->visual->red_mask; + xcontext->g_mask_output = xcontext->visual->green_mask; + xcontext->b_mask_output = xcontext->visual->blue_mask; + } + + return xcontext; +} + +/* This function cleans the X context. Closing the Display and unrefing the + caps for supported formats. */ +void +ximageutil_xcontext_clear (GstXContext * xcontext) +{ + g_return_if_fail (xcontext != NULL); + + if (xcontext->caps != NULL) + gst_caps_unref (xcontext->caps); + + if (xcontext->par) { + g_value_unset (xcontext->par); + g_free (xcontext->par); + } + + XCloseDisplay (xcontext->disp); + + g_free (xcontext); +} + +/* This function calculates the pixel aspect ratio based on the properties + * in the xcontext structure and stores it there. */ +void +ximageutil_calculate_pixel_aspect_ratio (GstXContext * xcontext) +{ + gint par[][2] = { + {1, 1}, /* regular screen */ + {16, 15}, /* PAL TV */ + {11, 10}, /* 525 line Rec.601 video */ + {54, 59} /* 625 line Rec.601 video */ + }; + gint i; + gint index; + gdouble ratio; + gdouble delta; + +#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1]))) + + /* first calculate the "real" ratio based on the X values; + * which is the "physical" w/h divided by the w/h in pixels of the display */ + ratio = (gdouble) (xcontext->widthmm * xcontext->height) + / (xcontext->heightmm * xcontext->width); + + /* DirectFB's X in 720x576 reports the physical dimensions wrong, so + * override here */ + if (xcontext->width == 720 && xcontext->height == 576) { + ratio = 4.0 * 576 / (3.0 * 720); + } + GST_DEBUG ("calculated pixel aspect ratio: %f", ratio); + + /* now find the one from par[][2] with the lowest delta to the real one */ + delta = DELTA (0); + index = 0; + + for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) { + gdouble this_delta = DELTA (i); + + if (this_delta < delta) { + index = i; + delta = this_delta; + } + } + + GST_DEBUG ("Decided on index %d (%d/%d)", index, + par[index][0], par[index][1]); + + if (xcontext->par) + g_free (xcontext->par); + xcontext->par = g_new0 (GValue, 1); + g_value_init (xcontext->par, GST_TYPE_FRACTION); + gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]); + GST_DEBUG ("set xcontext PAR to %d/%d\n", + gst_value_get_fraction_numerator (xcontext->par), + gst_value_get_fraction_denominator (xcontext->par)); +} + +static GstBufferClass *ximagesrc_buffer_parent_class = NULL; + +static void +gst_ximagesrc_buffer_finalize (GstXImageSrcBuffer * ximage) +{ + GstElement *parent; + + g_return_if_fail (ximage != NULL); + + parent = ximage->parent; + if (parent == NULL) { + g_warning ("XImageSrcBuffer->ximagesrc == NULL"); + goto beach; + } + + if (ximage->return_func) + ximage->return_func (parent, ximage); + +beach: + + GST_MINI_OBJECT_CLASS (ximagesrc_buffer_parent_class)->finalize + (GST_MINI_OBJECT (ximage)); + + return; +} + +void +gst_ximage_buffer_free (GstXImageSrcBuffer * ximage) +{ + /* make sure it is not recycled */ + ximage->width = -1; + ximage->height = -1; + gst_buffer_unref (GST_BUFFER (ximage)); +} + +static void +gst_ximagesrc_buffer_init (GstXImageSrcBuffer * ximage_buffer, gpointer g_class) +{ +#ifdef HAVE_XSHM + ximage_buffer->SHMInfo.shmaddr = ((void *) -1); + ximage_buffer->SHMInfo.shmid = -1; +#endif +} + +static void +gst_ximagesrc_buffer_class_init (gpointer g_class, gpointer class_data) +{ + GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class); + + ximagesrc_buffer_parent_class = g_type_class_peek_parent (g_class); + + mini_object_class->finalize = (GstMiniObjectFinalizeFunction) + gst_ximagesrc_buffer_finalize; +} + +static GType +gst_ximagesrc_buffer_get_type (void) +{ + static GType _gst_ximagesrc_buffer_type; + + if (G_UNLIKELY (_gst_ximagesrc_buffer_type == 0)) { + static const GTypeInfo ximagesrc_buffer_info = { + sizeof (GstBufferClass), + NULL, + NULL, + gst_ximagesrc_buffer_class_init, + NULL, + NULL, + sizeof (GstXImageSrcBuffer), + 0, + (GInstanceInitFunc) gst_ximagesrc_buffer_init, + NULL + }; + _gst_ximagesrc_buffer_type = g_type_register_static (GST_TYPE_BUFFER, + "GstXImageSrcBuffer", &ximagesrc_buffer_info, 0); + } + return _gst_ximagesrc_buffer_type; +} + +/* This function handles GstXImageSrcBuffer creation depending on XShm availability */ +GstXImageSrcBuffer * +gst_ximageutil_ximage_new (GstXContext * xcontext, + GstElement * parent, int width, int height, BufferReturnFunc return_func) +{ + GstXImageSrcBuffer *ximage = NULL; + gboolean succeeded = FALSE; + + ximage = + (GstXImageSrcBuffer *) gst_mini_object_new (GST_TYPE_XIMAGESRC_BUFFER); + + ximage->width = width; + ximage->height = height; + +#ifdef HAVE_XSHM + if (xcontext->use_xshm) { + ximage->ximage = XShmCreateImage (xcontext->disp, + xcontext->visual, xcontext->depth, + ZPixmap, NULL, &ximage->SHMInfo, ximage->width, ximage->height); + if (!ximage->ximage) { + GST_WARNING_OBJECT (parent, + "could not XShmCreateImage a %dx%d image", + ximage->width, ximage->height); + + /* Retry without XShm */ + xcontext->use_xshm = FALSE; + goto no_xshm; + } + + /* we have to use the returned bytes_per_line for our shm size */ + ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height; + ximage->SHMInfo.shmid = shmget (IPC_PRIVATE, ximage->size, + IPC_CREAT | 0777); + if (ximage->SHMInfo.shmid == -1) + goto beach; + + ximage->SHMInfo.shmaddr = shmat (ximage->SHMInfo.shmid, 0, 0); + if (ximage->SHMInfo.shmaddr == ((void *) -1)) + goto beach; + + /* Delete the SHM segment. It will actually go away automatically + * when we detach now */ + shmctl (ximage->SHMInfo.shmid, IPC_RMID, 0); + + ximage->ximage->data = ximage->SHMInfo.shmaddr; + ximage->SHMInfo.readOnly = FALSE; + + if (XShmAttach (xcontext->disp, &ximage->SHMInfo) == 0) + goto beach; + + XSync (xcontext->disp, FALSE); + } else + no_xshm: +#endif /* HAVE_XSHM */ + { + ximage->ximage = XCreateImage (xcontext->disp, + xcontext->visual, + xcontext->depth, + ZPixmap, 0, NULL, ximage->width, ximage->height, xcontext->bpp, 0); + if (!ximage->ximage) + goto beach; + + /* we have to use the returned bytes_per_line for our image size */ + ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height; + ximage->ximage->data = g_malloc (ximage->size); + + XSync (xcontext->disp, FALSE); + } + succeeded = TRUE; + + GST_BUFFER_DATA (ximage) = (guchar *) ximage->ximage->data; + GST_BUFFER_SIZE (ximage) = ximage->size; + + /* Keep a ref to our src */ + ximage->parent = gst_object_ref (parent); + ximage->return_func = return_func; +beach: + if (!succeeded) { + gst_ximage_buffer_free (ximage); + ximage = NULL; + } + + return ximage; +} + +/* This function destroys a GstXImageBuffer handling XShm availability */ +void +gst_ximageutil_ximage_destroy (GstXContext * xcontext, + GstXImageSrcBuffer * ximage) +{ + /* We might have some buffers destroyed after changing state to NULL */ + if (!xcontext) + goto beach; + + g_return_if_fail (ximage != NULL); + +#ifdef HAVE_XSHM + if (xcontext->use_xshm) { + if (ximage->SHMInfo.shmaddr != ((void *) -1)) { + XShmDetach (xcontext->disp, &ximage->SHMInfo); + XSync (xcontext->disp, 0); + shmdt (ximage->SHMInfo.shmaddr); + } + if (ximage->ximage) + XDestroyImage (ximage->ximage); + + } else +#endif /* HAVE_XSHM */ + { + if (ximage->ximage) { + XDestroyImage (ximage->ximage); + } + } + + XSync (xcontext->disp, FALSE); +beach: + if (ximage->parent) { + /* Release the ref to our parent */ + gst_object_unref (ximage->parent); + ximage->parent = NULL; + } + + return; +} diff --git a/sys/ximage/ximageutil.h b/sys/ximage/ximageutil.h new file mode 100644 index 0000000..517fc8e --- /dev/null +++ b/sys/ximage/ximageutil.h @@ -0,0 +1,182 @@ +/* GStreamer + * Copyright (C) <2005> Luca Ognibene <luogni@tin.it> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * 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_XIMAGEUTIL_H__ +#define __GST_XIMAGEUTIL_H__ + +#include <gst/gst.h> + +#ifdef HAVE_XSHM +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#endif /* HAVE_XSHM */ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#ifdef HAVE_XSHM +#include <X11/extensions/XShm.h> +#endif /* HAVE_XSHM */ + +#include <string.h> +#include <math.h> + +G_BEGIN_DECLS + +typedef struct _GstXContext GstXContext; +typedef struct _GstXWindow GstXWindow; +typedef struct _GstXImage GstXImage; +typedef struct _GstXImageSrcBuffer GstXImageSrcBuffer; + +/* Global X Context stuff */ +/** + * GstXContext: + * @disp: the X11 Display of this context + * @screen: the default Screen of Display @disp + * @screen_num: the Screen number of @screen + * @visual: the default Visual of Screen @screen + * @root: the root Window of Display @disp + * @white: the value of a white pixel on Screen @screen + * @black: the value of a black pixel on Screen @screen + * @depth: the color depth of Display @disp + * @bpp: the number of bits per pixel on Display @disp + * @endianness: the endianness of image bytes on Display @disp + * @width: the width in pixels of Display @disp + * @height: the height in pixels of Display @disp + * @widthmm: the width in millimeters of Display @disp + * @heightmm: the height in millimeters of Display @disp + * @par: the pixel aspect ratio calculated from @width, @widthmm and @height, + * @heightmm ratio + * @use_xshm: used to known wether of not XShm extension is usable or not even + * if the Extension is present + * @caps: the #GstCaps that Display @disp can accept + * + * Structure used to store various informations collected/calculated for a + * Display. + */ +struct _GstXContext { + Display *disp; + + Screen *screen; + gint screen_num; + + Visual *visual; + + Window root; + + gulong white, black; + + gint depth; + gint bpp; + gint endianness; + + gint width, height; + gint widthmm, heightmm; + + /* these are the output masks + * for buffers from ximagesrc + * and are in big endian */ + guint32 r_mask_output, g_mask_output, b_mask_output; + + GValue *par; /* calculated pixel aspect ratio */ + + gboolean use_xshm; + + GstCaps *caps; +}; + +/** + * GstXWindow: + * @win: the Window ID of this X11 window + * @width: the width in pixels of Window @win + * @height: the height in pixels of Window @win + * @internal: used to remember if Window @win was created internally or passed + * through the #GstXOverlay interface + * @gc: the Graphical Context of Window @win + * + * Structure used to store informations about a Window. + */ +struct _GstXWindow { + Window win; + gint width, height; + gboolean internal; + GC gc; +}; + +gboolean ximageutil_check_xshm_calls (GstXContext * xcontext); + +GstXContext *ximageutil_xcontext_get (GstElement *parent, + const gchar *display_name); +void ximageutil_xcontext_clear (GstXContext *xcontext); +void ximageutil_calculate_pixel_aspect_ratio (GstXContext * xcontext); + +/* custom ximagesrc buffer, copied from ximagesink */ + +/* BufferReturnFunc is called when a buffer is finalised */ +typedef void (*BufferReturnFunc) (GstElement *parent, GstXImageSrcBuffer *buf); + +/** + * GstXImageSrcBuffer: + * @parent: a reference to the element we belong to + * @ximage: the XImage of this buffer + * @width: the width in pixels of XImage @ximage + * @height: the height in pixels of XImage @ximage + * @size: the size in bytes of XImage @ximage + * + * Subclass of #GstBuffer containing additional information about an XImage. + */ +struct _GstXImageSrcBuffer { + GstBuffer buffer; + + /* Reference to the ximagesrc we belong to */ + GstElement *parent; + + XImage *ximage; + +#ifdef HAVE_XSHM + XShmSegmentInfo SHMInfo; +#endif /* HAVE_XSHM */ + + gint width, height; + size_t size; + + BufferReturnFunc return_func; +}; + + +GstXImageSrcBuffer *gst_ximageutil_ximage_new (GstXContext *xcontext, + GstElement *parent, int width, int height, BufferReturnFunc return_func); + +void gst_ximageutil_ximage_destroy (GstXContext *xcontext, + GstXImageSrcBuffer * ximage); + +/* Call to manually release a buffer */ +void gst_ximage_buffer_free (GstXImageSrcBuffer *ximage); + +#define GST_TYPE_XIMAGESRC_BUFFER (gst_ximagesrc_buffer_get_type()) +#define GST_IS_XIMAGESRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XIMAGESRC_BUFFER)) +#define GST_IS_XIMAGESRC_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_XIMAGESRC_BUFFER)) +#define GST_XIMAGESRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XIMAGESRC_BUFFER, GstXImageSrcBuffer)) +#define GST_XIMAGESRC_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_XIMAGESRC_BUFFER, GstXImageSrcBufferClass)) +#define GST_XIMAGESRC_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_XIMAGESRC_BUFFER, GstXImageSrcBufferClass)) + +G_END_DECLS + +#endif /* __GST_XIMAGEUTIL_H__ */ |