summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Caujolle-Bert <f1rmb@users.sourceforge.net>2001-04-24 20:53:00 +0000
committerDaniel Caujolle-Bert <f1rmb@users.sourceforge.net>2001-04-24 20:53:00 +0000
commitb45eeec7a33e6b7475ebf02e3635e7d37ed33544 (patch)
tree5dbd28fee8ed5052b96bf9ebaa02cc8c8aa1320b
parent8f4426252dba8db47beaea9b9956c03668c1a640 (diff)
downloadxine-lib-b45eeec7a33e6b7475ebf02e3635e7d37ed33544.tar.gz
xine-lib-b45eeec7a33e6b7475ebf02e3635e7d37ed33544.tar.bz2
Reunification of xine-lib and xine-output. Some code cleanups.
CVS patchset: 21 CVS date: 2001/04/24 20:53:00
-rw-r--r--acconfig.h15
-rw-r--r--configure.in56
-rwxr-xr-xcvscompile.sh2
-rw-r--r--include/Makefile.am33
-rw-r--r--m4/Makefile.am2
-rw-r--r--m4/alsa.m4175
-rw-r--r--m4/esd.m4164
-rw-r--r--src/Makefile.am2
-rw-r--r--src/audio_out/Makefile.am45
-rw-r--r--src/audio_out/audio_alsa_out.c761
-rw-r--r--src/audio_out/audio_alsa_out.h28
-rw-r--r--src/audio_out/audio_esd_out.c329
-rw-r--r--src/audio_out/audio_esd_out.h26
-rw-r--r--src/audio_out/audio_oss_out.c452
-rw-r--r--src/audio_out/audio_oss_out.h27
-rw-r--r--src/audio_out/resample.c67
-rw-r--r--src/audio_out/resample.h42
-rw-r--r--src/video_out/Makefile.am41
-rw-r--r--src/video_out/video_out_syncfb.c849
-rw-r--r--src/video_out/video_out_syncfb.h240
-rw-r--r--src/video_out/video_out_xshm.c968
-rw-r--r--src/video_out/video_out_xv.c903
-rw-r--r--src/video_out/yuv2rgb.c465
-rw-r--r--src/video_out/yuv2rgb.h81
-rw-r--r--src/video_out/yuv2rgb_mmx.c537
-rw-r--r--src/xine-engine/Makefile.am9
-rw-r--r--src/xine-engine/audio_out.h (renamed from include/audio_out.h)2
-rw-r--r--src/xine-engine/video_out.h (renamed from include/video_out.h)2
28 files changed, 6283 insertions, 40 deletions
diff --git a/acconfig.h b/acconfig.h
index 37dcbb455..aaf2d438b 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -27,3 +27,18 @@
/* Define this to skins directory location */
#undef XINE_SKINDIR
+
+/* Define this if you have X11R6 installed */
+#undef HAVE_X11
+
+/* Define this if you have libXv installed */
+#undef HAVE_XV
+
+/* Define this if you have libXinerama installed */
+#undef HAVE_XINERAMA
+
+/* Define this if you have Alsa (libasound) installed */
+#undef HAVE_ALSA
+
+/* Define this if you have ESD (libesd) installed */
+#undef HAVE_ESD
diff --git a/configure.in b/configure.in
index fcc58e22d..a897a82bc 100644
--- a/configure.in
+++ b/configure.in
@@ -140,6 +140,58 @@ fi
dnl
+dnl Checks for X11
+dnl
+AC_PATH_XTRA
+if test x"$no_x" != "xyes"; then
+ AC_DEFINE(HAVE_X11)
+fi
+AM_CONDITIONAL(HAVE_X11, test x"$no_x" != "xyes")
+
+
+dnl
+dnl Checks for Xv extension
+dnl
+
+AC_CHECK_LIB(Xv, XvShmCreateImage,
+ X_LIBS="$X_LIBS -lXv"
+ AC_DEFINE(HAVE_XV)
+ ac_have_xv="yes",,
+ $X_LIBS $X_PRE_LIBS -lXext $X_EXTRA_LIBS)
+AM_CONDITIONAL(HAVE_XV, test x$ac_have_xv = "xyes")
+
+
+dnl
+dnl Checks for Xinerama extension
+dnl
+
+AC_CHECK_LIB(Xinerama, XineramaQueryExtension,
+ X_LIBS="$X_LIBS -lXinerama"
+ AC_DEFINE(HAVE_XINERAMA)
+ ac_have_xinerama="yes",,
+ $X_LIBS $X_PRE_LIBS -lXext $X_EXTRA_LIBS)
+AM_CONDITIONAL(HAVE_XINERAMA, test x$ac_have_xinerama = "xyes")
+
+
+dnl
+dnl Alsa support
+dnl
+AM_PATH_ALSA(0.5.5,
+ AC_DEFINE(HAVE_ALSA),
+ AC_MSG_RESULT(*** All of ALSA dependent parts will be disabled ***))
+AM_CONDITIONAL(HAVE_ALSA, test x"$no_alsa" != "xyes")
+
+
+dnl
+dnl ESD support
+dnl
+AM_PATH_ESD(0.2.8,
+ AC_DEFINE(HAVE_ESD),
+ AC_MSG_RESULT(*** All of ESD dependent parts will be disabled ***))
+AM_CONDITIONAL(HAVE_ESD, test x"$no_esd" != "xyes")
+
+
+dnl
dnl
dnl
AC_CHECK_FUNC(getpwuid_r,AC_DEFINE(HAVE_GETPWUID_R))
@@ -314,7 +366,7 @@ AC_SUBST(w32_path)
dnl
dnl Some include paths ( !!! DO NOT REMOVE !!! )
dnl
-INCLUDES='-I$(top_srcdir) -I$(top_builddir) -I$(top_srcdir)/src -I$(top_builddir)/src -I$(top_srcdir)/src/xine-engine -I$(top_builddir)/src/xine-engine -I$(top_srcdir)/include -I$(top_builddir/)/include'
+INCLUDES='-I$(top_srcdir) -I$(top_builddir) -I$(top_srcdir)/src -I$(top_builddir)/src -I$(top_srcdir)/src/xine-engine -I$(top_builddir)/src/xine-engine'
AC_SUBST(INCLUDES)
@@ -341,6 +393,8 @@ Makefile
include/Makefile
include/xine.h.tmpl
src/Makefile
+src/audio_out/Makefile
+src/video_out/Makefile
src/demuxers/Makefile
src/libmpeg2/Makefile
src/libac3/Makefile
diff --git a/cvscompile.sh b/cvscompile.sh
index 3ac246e01..d671af41c 100755
--- a/cvscompile.sh
+++ b/cvscompile.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Run this to generate all the initial Makefiles, etc.
-m4_files="_xine.m4"
+m4_files="_xine.m4 alsa.m4 esd.m4"
if test -d m4; then
rm -f acinclude.m4
for m4f in $m4_files; do
diff --git a/include/Makefile.am b/include/Makefile.am
index 9f16758c9..78923b1e5 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -4,8 +4,8 @@
EXTRA_DIST = xine.h.tmpl.in
-include_HEADERS = audio_out.h video_out.h xine.h
-
+includedir = $(prefix)/include
+include_HEADERS = xine.h
xine.h: xine.h.tmpl
@echo "creating xine.h"; \
@@ -17,35 +17,6 @@ xine.h: xine.h.tmpl
debug:
-install-includeHEADERS: $(include_HEADERS)
- @$(NORMAL_INSTALL)
- $(mkinstalldirs) $(DESTDIR)$(includedir)/xine
- @list='$(include_HEADERS)'; for p in $$list; do \
- if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \
- if test "$$p" != "xine.h"; then \
- echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/xine/$$p"; \
- $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/xine/$$p; \
- else \
- echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p"; \
- $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p; \
- fi; \
- done
-
-
-##
-## Remove them
-##
-uninstall-includeHEADERS:
- @$(NORMAL_UNINSTALL)
- list='$(include_HEADERS)'; for p in $$list; do \
- if test "$$p" != "xine.h"; then \
- rm -f $(DESTDIR)$(includedir)/xine/$$p; \
- else \
- rm -f $(DESTDIR)$(includedir)/$$p; \
- fi; \
- done
-
-
mostlyclean-generic:
-rm -f *~ \#* .*~ .\#*
diff --git a/m4/Makefile.am b/m4/Makefile.am
index a06ac6530..ecad1ffc2 100644
--- a/m4/Makefile.am
+++ b/m4/Makefile.am
@@ -4,7 +4,7 @@
m4datadir = @ACLOCAL_DIR@
m4data_DATA = xine.m4
-EXTRA_DIST = _xine.m4 $(m4data_DATA)
+EXTRA_DIST = _xine.m4 alsa.m4 esd.m4 $(m4data_DATA)
debug:
diff --git a/m4/alsa.m4 b/m4/alsa.m4
new file mode 100644
index 000000000..1bf79078b
--- /dev/null
+++ b/m4/alsa.m4
@@ -0,0 +1,175 @@
+dnl Configure paths/version for ALSA
+dnl
+dnl Copyright (C) 2000 Daniel Caujolle-Bert <lobadia@club-internet.fr>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+dnl
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a configuration
+dnl script generated by Autoconf, you may include it under the same
+dnl distribution terms that you use for the rest of that program.
+dnl
+dnl USAGE:
+dnl AM_PATH_ALSA([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for ALSA, then
+dnl AC_SUBST() for ALSA_CFLAGS, ALSA_LIBS and ALSA_STATIC_LIB,
+dnl AC_DEFINE() HAVE_GL,
+dnl $no_alsa is set to "yes" if alsa isn't found.
+dnl
+AC_DEFUN(AM_PATH_ALSA,
+ [
+ AC_ARG_ENABLE(alsa, [ --disable-alsa Do not build ALSA support],,)
+ AC_ARG_WITH(alsa-prefix,[ --with-alsa-prefix=pfx Prefix where alsa is installed (optional)],
+ alsa_prefix="$withval", alsa_prefix="")
+ AC_ARG_WITH(alsa-exec-prefix,[ --with-alsa-exec-prefix=pfx Exec prefix where alsa is installed (optional)],
+ alsa_exec_prefix="$withval", alsa_exec_prefix="")
+ AC_ARG_ENABLE(alsatest, [ --disable-alsatest Do not try to compile and run a test alsa program],, enable_alsatest=yes)
+
+ no_alsa="yes"
+
+if test x"$enable_alsa" != "xno"; then
+
+ if test x$alsa_prefix != x ; then
+ ALSA_LIBS="-L$alsa_prefix/lib"
+ ALSA_STATIC_LIB="$alsa_prefix"
+ ALSA_CFLAGS="-I$alsa_prefix/include"
+ fi
+ if test x$alsa_exec_prefix != x ; then
+ ALSA_LIBS="-L$alsa_exec_prefix/lib"
+ ALSA_STATIC_LIB="$alsa_exec_prefix"
+ ALSA_CFLAGS="-I$alsa_exec_prefix/include"
+ fi
+
+ ALSA_LIBS="-lasound $ALSA_LIBS"
+ if test x$ALSA_STATIC_LIB != x; then
+ ALSA_STATIC_LIB="$ALSA_STATIC_LIB/lib/libasound.a"
+ else
+ ALSA_STATIC_LIB="/usr/lib/libasound.a"
+ fi
+ ALSA_CFLAGS="$ALSA_CFLAGS"
+
+ min_alsa_version=ifelse([$1], ,0.1.1,$1)
+ AC_MSG_CHECKING(for ALSA version >= $min_alsa_version)
+ if test "x$enable_alsatest" = "xyes" ; then
+ no_alsa=""
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $ALSA_CFLAGS"
+ LIBS="$ALSA_LIBS $LIBS"
+dnl
+dnl Now check if the installed ALSA is sufficiently new.
+dnl
+ AC_LANG_SAVE()
+ AC_LANG_C()
+ rm -f conf.alsatest
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/asoundlib.h>
+
+int main() {
+ int major, minor, micro;
+ char *tmp_version;
+
+ system("touch conf.alsatest");
+
+ tmp_version = strdup("$min_alsa_version");
+ if(sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+ printf("%s, bad version string\n", "$min_alsa_version");
+ exit(1);
+ }
+
+ #if !defined(SND_LIB_MAJOR) && defined(SOUNDLIB_VERSION_MAJOR)
+ #define SND_LIB_MAJOR SOUNDLIB_VERSION_MAJOR
+ #endif
+ #if !defined(SND_LIB_MINOR) && defined(SOUNDLIB_VERSION_MINOR)
+ #define SND_LIB_MINOR SOUNDLIB_VERSION_MINOR
+ #endif
+ #if !defined(SND_LIB_SUBMINOR) && defined(SOUNDLIB_VERSION_SUBMINOR)
+ #define SND_LIB_SUBMINOR SOUNDLIB_VERSION_SUBMINOR
+ #endif
+
+ if((SND_LIB_MAJOR > major) ||
+ ((SND_LIB_MAJOR == major) && (SND_LIB_MINOR > minor)) ||
+ ((SND_LIB_MAJOR == major) && (SND_LIB_MINOR == minor) && (SND_LIB_SUBMINOR >= micro))) {
+ return 0;
+ }
+ else {
+ printf("\n*** An old version of ALSA (%d.%d.%d) was found.\n",
+ SND_LIB_MAJOR, SND_LIB_MINOR, SND_LIB_SUBMINOR);
+ printf("*** You need a version of ALSA newer than %d.%d.%d. The latest version of\n", major, minor, micro);
+ printf("*** ALSA is always available from: http://www.alsa-drivers.org/\n");
+ printf("***\n");
+ printf("*** If you have already installed a sufficiently new version\n");
+ printf("*** the easiest way to fix this is to remove the old version, and\n");
+ printf("*** install a new one.\n");
+ }
+ return 1;
+}
+],, no_alsa=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+
+ if test "x$no_alsa" = x ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_RESULT(no)
+ if test -f conf.alsatest ; then
+ :
+ else
+ echo "*** Could not run ALSA test program, checking why..."
+ CFLAGS="$CFLAGS $ALSA_CFLAGS"
+ LIBS="$LIBS $ALSA_LIBS"
+ AC_TRY_LINK([
+#include <sys/asoudlib.h>
+#include <stdio.h>
+],
+ [return ((SND_LIB_MAJOR) || (SND_LIB_MINOR) || (SND_LIB_SUBMINOR));],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding ALSA or finding the wrong"
+ echo "*** version of ALSA. If it is not finding ALSA, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+ echo "***"],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means ALSA was incorrectly installed."])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+
+ ALSA_CFLAGS=""
+ ALSA_STATIC_LIB=""
+ ALSA_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+
+fi
+
+ AC_SUBST(ALSA_CFLAGS)
+ AC_SUBST(ALSA_STATIC_LIB)
+ AC_SUBST(ALSA_LIBS)
+ AC_LANG_RESTORE()
+ rm -f conf.alsatest
+])
+
diff --git a/m4/esd.m4 b/m4/esd.m4
new file mode 100644
index 000000000..39b378988
--- /dev/null
+++ b/m4/esd.m4
@@ -0,0 +1,164 @@
+# Configure paths for ESD
+# Manish Singh 98-9-30
+# stolen back from Frank Belew
+# stolen from Manish Singh
+# Shamelessly stolen from Owen Taylor
+
+dnl AM_PATH_ESD([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for ESD, and define ESD_CFLAGS and ESD_LIBS
+dnl
+AC_DEFUN(AM_PATH_ESD,
+[dnl
+dnl Get the cflags and libraries from the esd-config script
+dnl
+AC_ARG_WITH(esd-prefix,[ --with-esd-prefix=PFX Prefix where ESD is installed (optional)],
+ esd_prefix="$withval", esd_prefix="")
+AC_ARG_WITH(esd-exec-prefix,[ --with-esd-exec-prefix=PFX Exec prefix where ESD is installed (optional)],
+ esd_exec_prefix="$withval", esd_exec_prefix="")
+AC_ARG_ENABLE(esdtest, [ --disable-esdtest Do not try to compile and run a test ESD program],
+ , enable_esdtest=yes)
+
+ if test x$esd_exec_prefix != x ; then
+ esd_args="$esd_args --exec-prefix=$esd_exec_prefix"
+ if test x${ESD_CONFIG+set} != xset ; then
+ ESD_CONFIG=$esd_exec_prefix/bin/esd-config
+ fi
+ fi
+ if test x$esd_prefix != x ; then
+ esd_args="$esd_args --prefix=$esd_prefix"
+ if test x${ESD_CONFIG+set} != xset ; then
+ ESD_CONFIG=$esd_prefix/bin/esd-config
+ fi
+ fi
+
+ AC_PATH_PROG(ESD_CONFIG, esd-config, no)
+ min_esd_version=ifelse([$1], ,0.2.7,$1)
+ AC_MSG_CHECKING(for ESD - version >= $min_esd_version)
+ no_esd=""
+ if test "$ESD_CONFIG" = "no" ; then
+ no_esd=yes
+ else
+ ESD_CFLAGS=`$ESD_CONFIG $esdconf_args --cflags`
+ ESD_LIBS=`$ESD_CONFIG $esdconf_args --libs`
+
+ esd_major_version=`$ESD_CONFIG $esd_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ esd_minor_version=`$ESD_CONFIG $esd_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ esd_micro_version=`$ESD_CONFIG $esd_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+ if test "x$enable_esdtest" = "xyes" ; then
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $ESD_CFLAGS"
+ LIBS="$LIBS $ESD_LIBS"
+dnl
+dnl Now check if the installed ESD is sufficiently new. (Also sanity
+dnl checks the results of esd-config to some extent
+dnl
+ rm -f conf.esdtest
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <esd.h>
+
+char*
+my_strdup (char *str)
+{
+ char *new_str;
+
+ if (str)
+ {
+ new_str = malloc ((strlen (str) + 1) * sizeof(char));
+ strcpy (new_str, str);
+ }
+ else
+ new_str = NULL;
+
+ return new_str;
+}
+
+int main ()
+{
+ int major, minor, micro;
+ char *tmp_version;
+
+ system ("touch conf.esdtest");
+
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = my_strdup("$min_esd_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+ printf("%s, bad version string\n", "$min_esd_version");
+ exit(1);
+ }
+
+ if (($esd_major_version > major) ||
+ (($esd_major_version == major) && ($esd_minor_version > minor)) ||
+ (($esd_major_version == major) && ($esd_minor_version == minor) && ($esd_micro_version >= micro)))
+ {
+ return 0;
+ }
+ else
+ {
+ printf("\n*** 'esd-config --version' returned %d.%d.%d, but the minimum version\n", $esd_major_version, $esd_minor_version, $esd_micro_version);
+ printf("*** of ESD required is %d.%d.%d. If esd-config is correct, then it is\n", major, minor, micro);
+ printf("*** best to upgrade to the required version.\n");
+ printf("*** If esd-config was wrong, set the environment variable ESD_CONFIG\n");
+ printf("*** to point to the correct copy of esd-config, and remove the file\n");
+ printf("*** config.cache before re-running configure\n");
+ return 1;
+ }
+}
+
+],, no_esd=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ if test "x$no_esd" = x ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_RESULT(no)
+ if test "$ESD_CONFIG" = "no" ; then
+ echo "*** The esd-config script installed by ESD could not be found"
+ echo "*** If ESD was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the ESD_CONFIG environment variable to the"
+ echo "*** full path to esd-config."
+ else
+ if test -f conf.esdtest ; then
+ :
+ else
+ echo "*** Could not run ESD test program, checking why..."
+ CFLAGS="$CFLAGS $ESD_CFLAGS"
+ LIBS="$LIBS $ESD_LIBS"
+ AC_TRY_LINK([
+#include <stdio.h>
+#include <esd.h>
+], [ return 0; ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding ESD or finding the wrong"
+ echo "*** version of ESD. If it is not finding ESD, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means ESD was incorrectly installed"
+ echo "*** or that you have moved ESD since it was installed. In the latter case, you"
+ echo "*** may want to edit the esd-config script: $ESD_CONFIG" ])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ ESD_CFLAGS=""
+ ESD_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(ESD_CFLAGS)
+ AC_SUBST(ESD_LIBS)
+ rm -f conf.esdtest
+])
diff --git a/src/Makefile.am b/src/Makefile.am
index 822ab3e18..f4864d330 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
-SUBDIRS = input libmpeg2 libspudec demuxers \
+SUBDIRS = audio_out video_out input libmpeg2 libspudec demuxers \
libac3 libmpg123 libw32dll xine-engine
debug:
diff --git a/src/audio_out/Makefile.am b/src/audio_out/Makefile.am
new file mode 100644
index 000000000..220f5991d
--- /dev/null
+++ b/src/audio_out/Makefile.am
@@ -0,0 +1,45 @@
+CFLAGS = @GLOBAL_CFLAGS@ -DXINE_COMPILE
+
+EXTRA_DIST = audio_alsa_out.c audio_esd_out.c
+
+if HAVE_ALSA
+alsa_module = xineplug_ao_out_alsa.la
+endif
+
+if HAVE_ESD
+esd_module = xineplug_ao_out_esd.la
+endif
+
+##
+# IMPORTANT:
+# ---------
+# All of xine audio out plugins should be named like the
+# scheme "xineplug_ao_out_"
+#
+##lib_LTLIBRARIES = xineplug_ao_out_oss.la $(alsa_module) $(esd_module)
+lib_LTLIBRARIES =
+
+##xineplug_ao_out_oss_la_SOURCES = audio_oss_out.c resample.c
+##xineplug_ao_out_oss_la_LDFLAGS = -avoid-version -module
+
+##xineplug_ao_out_alsa_la_SOURCES = audio_alsa_out.c resample.c
+##xineplug_ao_out_alsa_la_LDFLAGS = -avoid-version -module
+
+##xineplug_ao_out_esd_la_SOURCES = audio_esd_out.c resample.c
+##xineplug_ao_out_esd_la_LDFLAGS = -avoid-version -module
+
+noinst_HEADERS = audio_oss_out.h audio_alsa_out.h audio_esd_out.h resample.h
+
+
+debug:
+ $(MAKE) CFLAGS="$(DEBUG_CFLAGS)"
+
+
+mostlyclean-generic:
+ -rm -f *~ \#* .*~ .\#*
+
+
+maintainer-clean-generic:
+ -@echo "This command is intended for maintainers to use;"
+ -@echo "it deletes files that may require special tools to rebuild."
+ -rm -f Makefile.in
diff --git a/src/audio_out/audio_alsa_out.c b/src/audio_out/audio_alsa_out.c
new file mode 100644
index 000000000..95405511f
--- /dev/null
+++ b/src/audio_out/audio_alsa_out.c
@@ -0,0 +1,761 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: audio_alsa_out.c,v 1.1 2001/04/24 20:53:00 f1rmb Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/asoundlib.h>
+//#include <linux/asound.h>
+//#include <linux/asequencer.h>
+//#include <linux/asoundid.h>
+
+#include <inttypes.h>
+#include "xine/xine.h"
+#include "xine/monitor.h"
+#include "xine/audio_out.h"
+#include "xine/metronom.h"
+#include "resample.h"
+#include "xine/ac3.h"
+#include "xine/utils.h"
+
+#define AUDIO_NUM_FRAGMENTS 15
+#define AUDIO_FRAGMENT_SIZE 8192
+
+#define GAP_TOLERANCE 15000
+#define MAX_MASTER_CLOCK_DIV 5000
+
+extern uint32_t xine_debug;
+
+
+typedef struct _audio_alsa_globals {
+
+ snd_pcm_t *front_handle;
+
+ int32_t output_sample_rate, input_sample_rate;
+ uint32_t num_channels;
+
+ uint32_t bytes_in_buffer; /* number of bytes written to audio hardware */
+ uint32_t last_vpts; /* vpts at which last written package ends */
+
+ uint32_t sync_vpts; /* this syncpoint is used as a starting point */
+ uint32_t sync_bytes_in_buffer; /* for vpts <-> samplecount assoc */
+
+ int audio_step; /* pts per 32 768 samples (sample = #bytes/2) */
+ int32_t bytes_per_kpts; /* bytes per 1024/90000 sec */
+
+ int16_t *zero_space;
+
+ int audio_started;
+ int pcm_default_card;
+ int pcm_default_device;
+
+ int direction;
+ int mode;
+ int start_mode;
+ int stop_mode;
+ int format;
+ int rate;
+ int voices;
+ int interleave;
+ int frag_size;
+ int frag_count;
+ int pcm_len;
+
+} audio_alsa_globals_t;
+
+static audio_alsa_globals_t gAudioALSA;
+
+/* ------------------------------------------------------------------------- */
+/*
+ *
+ */
+static void alsa_set_frag(int fragment_size, int fragment_count) {
+ snd_pcm_channel_params_t params;
+ snd_pcm_channel_setup_t setup;
+ snd_pcm_format_t format;
+ int err;
+
+ memset(&params, 0, sizeof(params));
+
+ params.mode = gAudioALSA.mode;
+ params.channel = gAudioALSA.direction;
+ params.start_mode = gAudioALSA.start_mode;
+ params.stop_mode = gAudioALSA.stop_mode;
+ params.buf.block.frag_size = fragment_size;
+ params.buf.block.frags_max = fragment_count;
+ params.buf.block.frags_min = 1;
+
+ memset(&format, 0, sizeof(format));
+ format.format = gAudioALSA.format;
+ format.rate = gAudioALSA.rate;
+ format.voices = gAudioALSA.voices;
+ format.interleave = gAudioALSA.interleave;
+ memcpy(&params.format, &format, sizeof(format));
+
+ snd_pcm_playback_flush(gAudioALSA.front_handle);
+
+ if((err = snd_pcm_channel_params(gAudioALSA.front_handle, &params)) < 0) {
+ perr("snd_pcm_channel_params() failed: %s\n", snd_strerror(err));
+ return;
+ }
+ if((err = snd_pcm_playback_prepare(gAudioALSA.front_handle)) < 0) {
+ perr("snd_pcm_channel_prepare() failed: %s\n", snd_strerror(err));
+ return;
+ }
+
+ memset(&setup, 0, sizeof(setup));
+ setup.mode = gAudioALSA.mode;
+ setup.channel = gAudioALSA.direction;
+ if((err = snd_pcm_channel_setup(gAudioALSA.front_handle, &setup)) < 0) {
+ perr("snd_pcm_channel_setup() failed: %s\n", snd_strerror(err));
+ return;
+ }
+
+ gAudioALSA.frag_size = fragment_size;
+ gAudioALSA.frag_count = fragment_count;
+
+ gAudioALSA.pcm_len = fragment_size *
+ (snd_pcm_format_width(gAudioALSA.format) / 8) *
+ gAudioALSA.voices;
+
+ // perr("PCM len = %d\n", gAudioALSA.pcm_len);
+ if(gAudioALSA.zero_space)
+ free(gAudioALSA.zero_space);
+
+ gAudioALSA.zero_space = (int16_t *) malloc(gAudioALSA.frag_size);
+ memset(gAudioALSA.zero_space,
+ (int16_t) snd_pcm_format_silence(gAudioALSA.format),
+ gAudioALSA.frag_size);
+}
+/* ------------------------------------------------------------------------- */
+/*
+ * open the audio device for writing to
+ */
+static int ao_open(uint32_t bits, uint32_t rate, int ao_mode) {
+ int channels;
+ int subdevice = 0;
+ int direction = SND_PCM_OPEN_PLAYBACK;
+ snd_pcm_format_t pcm_format;
+ snd_pcm_channel_setup_t pcm_chan_setup;
+ snd_pcm_channel_params_t pcm_chan_params;
+ snd_pcm_channel_info_t pcm_chan_info;
+ int err;
+ int mode;
+
+
+ switch (ao_mode) {
+
+ case AO_MODE_STEREO:
+ case AO_MODE_AC3:
+ channels = 2;
+ break;
+
+ case AO_MODE_MONO:
+ channels = 1;
+ break;
+
+ default:
+ return 0;
+ break;
+ }
+
+ xprintf (VERBOSE|AUDIO, "bits = %d, rate = %d, channels = %d\n",
+ bits, rate, channels);
+
+#warning "FIXME in libAC3"
+ if(!rate)
+ return 0;
+
+ if(gAudioALSA.front_handle != NULL) {
+
+ if(rate == gAudioALSA.input_sample_rate)
+ return 1;
+
+ snd_pcm_close(gAudioALSA.front_handle);
+ }
+
+ gAudioALSA.input_sample_rate = rate;
+ gAudioALSA.bytes_in_buffer = 0;
+ gAudioALSA.last_vpts = 0;
+ gAudioALSA.sync_vpts = 0;
+ gAudioALSA.sync_bytes_in_buffer = 0;
+ gAudioALSA.audio_started = 0;
+ gAudioALSA.direction = SND_PCM_CHANNEL_PLAYBACK;
+
+ if (ao_mode == AO_MODE_AC3) {
+ gAudioALSA.pcm_default_device = 2;
+ mode = SND_PCM_MODE_BLOCK;
+ }
+ else {
+ mode = SND_PCM_MODE_BLOCK;
+ }
+
+ gAudioALSA.mode = mode;
+
+ if((err = snd_pcm_open_subdevice(&gAudioALSA.front_handle,
+ gAudioALSA.pcm_default_card,
+ gAudioALSA.pcm_default_device,
+ subdevice, direction
+// | SND_PCM_OPEN_NONBLOCK)) < 0) {
+ )) < 0) {
+ perr("snd_pcm_open_subdevice() failed: %s\n", snd_strerror(err));
+ return 0;
+ }
+
+ memset(&pcm_chan_info, 0, sizeof(snd_pcm_channel_info_t));
+ if((err = snd_pcm_channel_info(gAudioALSA.front_handle,
+ &pcm_chan_info)) < 0) {
+ perr("snd_pcm_channel_info() failed: %s\n", snd_strerror(err));
+ return 0;
+ }
+
+ memset(&pcm_chan_params, 0, sizeof(snd_pcm_channel_params_t));
+ memset(&pcm_format, 0, sizeof(snd_pcm_format_t));
+ /* set sample size */
+ switch(bits) {
+ case 8:
+ pcm_format.format = SND_PCM_SFMT_S8;
+ break;
+
+ case 16:
+ pcm_format.format = SND_PCM_SFMT_S16;
+ break;
+
+ case 24:
+ pcm_format.format = SND_PCM_SFMT_S24;
+ break;
+
+ case 32:
+ pcm_format.format = SND_PCM_SFMT_S32;
+ break;
+
+ default:
+ perr("sample format %d unsupported\n", bits);
+ break;
+ }
+ gAudioALSA.format = pcm_format.format;
+
+ xprintf (VERBOSE|AUDIO, "format name = '%s'\n",
+ snd_pcm_get_format_name(pcm_format.format));
+
+
+ pcm_format.voices = gAudioALSA.voices = channels;
+ pcm_format.rate = gAudioALSA.rate = rate;
+ pcm_format.interleave = gAudioALSA.interleave = 1;
+
+ gAudioALSA.num_channels = channels;
+
+ xprintf (VERBOSE|AUDIO, "audio channels = %d ao_mode = %d\n",
+ gAudioALSA.num_channels,ao_mode);
+
+ if(rate > pcm_chan_info.max_rate)
+ gAudioALSA.output_sample_rate = pcm_chan_info.max_rate;
+ else
+ gAudioALSA.output_sample_rate = gAudioALSA.input_sample_rate;
+
+ gAudioALSA.audio_step = (uint32_t) 90000
+ * (uint32_t) 32768 / gAudioALSA.input_sample_rate;
+
+ gAudioALSA.bytes_per_kpts = gAudioALSA.output_sample_rate
+ * gAudioALSA.num_channels * 2 * 1024 / 90000;
+
+ xprintf (VERBOSE|AUDIO, "%d input samples/sec %d output samples/sec\n",
+ rate, gAudioALSA.output_sample_rate);
+ xprintf (VERBOSE|AUDIO, "audio_out : audio_step %d pts per 32768 samples\n",
+ gAudioALSA.audio_step);
+
+ metronom_set_audio_rate (gAudioALSA.audio_step);
+
+ memcpy(&pcm_chan_params.format, &pcm_format, sizeof(snd_pcm_format_t));
+
+ pcm_chan_params.mode = mode;
+ pcm_chan_params.channel = gAudioALSA.direction;
+
+ pcm_chan_params.start_mode = SND_PCM_START_FULL;
+ //pcm_chan_params.start_mode = SND_PCM_START_DATA;
+ //pcm_chan_params.stop_mode = SND_PCM_STOP_STOP;
+ pcm_chan_params.stop_mode = SND_PCM_STOP_ROLLOVER;
+
+ gAudioALSA.start_mode = pcm_chan_params.start_mode;
+ gAudioALSA.stop_mode = pcm_chan_params.stop_mode;
+
+ if (ao_mode == AO_MODE_AC3) {
+ pcm_chan_params.digital.dig_valid = 1;
+ pcm_chan_params.digital.dig_status[0] = SND_PCM_DIG0_NONAUDIO;
+ pcm_chan_params.digital.dig_status[0] |= SND_PCM_DIG0_PROFESSIONAL;
+ pcm_chan_params.digital.dig_status[0] |= SND_PCM_DIG0_PRO_FS_48000;
+ pcm_chan_params.digital.dig_status[3] = SND_PCM_DIG3_CON_FS_48000;
+ }
+
+ snd_pcm_playback_flush(gAudioALSA.front_handle);
+ if((err = snd_pcm_channel_params(gAudioALSA.front_handle,
+ &pcm_chan_params)) < 0) {
+ perr("snd_pcm_channel_params() failed: %s\n", snd_strerror(err));
+ return 0;
+ }
+ if((err = snd_pcm_playback_prepare(gAudioALSA.front_handle)) < 0) {
+ perr("snd_pcm_channel_prepare() failed: %s\n", snd_strerror(err));
+ return 0;
+ }
+
+ pcm_chan_setup.mode = mode;
+ pcm_chan_setup.channel = gAudioALSA.direction;
+
+ if((err = snd_pcm_channel_setup(gAudioALSA.front_handle,
+ &pcm_chan_setup)) < 0) {
+ perr("snd_pcm_channel_setup() failed: %s\n", snd_strerror(err));
+ return 0;
+ }
+
+ printf ("actual rate: %d\n", pcm_chan_setup.format.rate);
+
+ alsa_set_frag(1536, 6);
+
+ gAudioALSA.bytes_in_buffer = 0;
+
+ return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+/*
+ *
+ */
+static void ao_fill_gap (uint32_t pts_len) {
+ int num_bytes = pts_len * gAudioALSA.bytes_per_kpts / 1024;
+
+ num_bytes = (num_bytes / 4) * 4;
+
+ gAudioALSA.bytes_in_buffer += num_bytes;
+
+ printf ("audio_alsa_out: inserting %d 0-bytes to fill a gap of %d pts\n",
+ num_bytes, pts_len);
+
+ while (num_bytes>0) {
+ if (num_bytes>gAudioALSA.frag_size) {
+ snd_pcm_write(gAudioALSA.front_handle, gAudioALSA.zero_space,
+ gAudioALSA.frag_size);
+ num_bytes -= gAudioALSA.frag_size;
+ } else {
+ int old_frag_size = gAudioALSA.frag_size;
+
+ alsa_set_frag(num_bytes, 6);
+
+ snd_pcm_write(gAudioALSA.front_handle, gAudioALSA.zero_space, num_bytes);
+
+ alsa_set_frag(old_frag_size, 6);
+
+ num_bytes = 0;
+ }
+ }
+
+ gAudioALSA.last_vpts += pts_len ;
+}
+
+/* ------------------------------------------------------------------------- */
+/*
+ *
+ */
+static uint32_t ao_get_current_vpts (void) {
+ int pos;
+ snd_pcm_channel_status_t pcm_stat;
+ int err;
+ int32_t diff;
+ uint32_t vpts;
+
+
+ if (gAudioALSA.audio_started) {
+ memset(&pcm_stat, 0, sizeof(snd_pcm_channel_status_t));
+ pcm_stat.channel = SND_PCM_CHANNEL_PLAYBACK;
+ if((err = snd_pcm_channel_status(gAudioALSA.front_handle,
+ &pcm_stat)) < 0) {
+ //Hide error report
+ perr("snd_pcm_channel_status() failed: %s\n", snd_strerror(err));
+ return 0;
+ }
+ pos = pcm_stat.scount;
+ }
+ else {
+ pos = 0;
+ }
+
+ diff = gAudioALSA.sync_bytes_in_buffer - pos;
+
+ vpts = gAudioALSA.sync_vpts - diff * 1024 / gAudioALSA.bytes_per_kpts;
+
+ xprintf (AUDIO|VERBOSE,"audio_alsa_out: get_current_vpts pos=%d diff=%d "
+ "vpts=%d sync_vpts=%d sync_bytes_in_buffer %d\n", pos, diff,
+ vpts, gAudioALSA.sync_vpts,gAudioALSA.sync_bytes_in_buffer);
+
+ return vpts;
+}
+
+/* ------------------------------------------------------------------------- */
+/*
+ *
+ */
+static void ao_put_samples(int16_t* output_samples,
+ uint32_t num_samples, uint32_t pts_) {
+ uint32_t vpts;
+ uint32_t audio_vpts;
+ uint32_t master_vpts;
+ int32_t diff, gap;
+ int bDropPackage = 0;
+ snd_pcm_channel_status_t status_front;
+ int err;
+ uint16_t sample_buffer[gAudioALSA.frag_size];
+
+
+ xprintf(VERBOSE|AUDIO, "Audio : play %d samples at pts %d pos %d \n",
+ num_samples, pts_, gAudioALSA.bytes_in_buffer);
+
+ if (gAudioALSA.front_handle == NULL)
+ return;
+
+ // if(gAudioALSA.frag_size != num_samples) {
+ // alsa_set_frag(num_samples, 6);
+ // }
+
+ vpts = metronom_got_audio_samples (pts_, num_samples);
+
+ /*
+ * check if these samples "fit" in the audio output buffer
+ * or do we have an audio "gap" here?
+ */
+
+ gap = vpts - gAudioALSA.last_vpts;
+
+ xprintf (VERBOSE|AUDIO, "audio_alsa_out: got %d samples, vpts=%d, "
+ "last_vpts=%d\n", num_samples, vpts, gAudioALSA.last_vpts);
+
+ if (gap > GAP_TOLERANCE) {
+ // ao_fill_gap (gap);
+ }
+ else if (gap < -GAP_TOLERANCE) {
+ bDropPackage = 1;
+ }
+
+ /*
+ * sync on master clock
+ */
+
+ audio_vpts = ao_get_current_vpts () ;
+ master_vpts = metronom_get_current_time ();
+ diff = audio_vpts - master_vpts;
+
+ xprintf (VERBOSE|AUDIO,"audio_alsa_out: syncing on master clock: "
+ "audio_vpts=%d master_vpts=%d\n", audio_vpts, master_vpts);
+
+ /*
+ * method 1 : resampling
+ */
+
+ /*
+ */
+
+ /*
+ * method 2: adjust master clock
+ */
+
+
+ if (abs(diff) > MAX_MASTER_CLOCK_DIV) {
+ printf ("master clock adjust time %d -> %d\n", master_vpts, audio_vpts);
+ metronom_adjust_clock (audio_vpts);
+ }
+
+ /*
+ * resample and output samples
+ */
+ if (!bDropPackage) {
+ int num_output_samples =
+ num_samples
+ * gAudioALSA.output_sample_rate
+ / gAudioALSA.input_sample_rate;
+
+ if(num_output_samples != gAudioALSA.frag_size)
+ alsa_set_frag(num_output_samples, 6);
+
+ if (num_output_samples != num_samples ) {
+ audio_out_resample_stereo (output_samples, num_samples,
+ sample_buffer, num_output_samples);
+ snd_pcm_write(gAudioALSA.front_handle, (void*)sample_buffer,
+ num_output_samples * 2 * gAudioALSA.num_channels);
+ }
+ else {
+ snd_pcm_write(gAudioALSA.front_handle, (void*)output_samples,
+ num_samples * 2 * gAudioALSA.num_channels);
+ }
+
+ memset(&status_front, 0, sizeof(snd_pcm_channel_status_t));
+ if((err = snd_pcm_channel_status(gAudioALSA.front_handle,
+ &status_front)) < 0) {
+ perr("snd_pcm_channel_status() failed: %s\n", snd_strerror(err));
+ }
+
+ /* Hummm, this seems made mistakes (flushing isnt good here). */
+ /*
+ if(status_front.underrun) {
+ perr("underrun, resetting front channel\n");
+ snd_pcm_channel_flush(gAudioALSA.front_handle, channel);
+ snd_pcm_playback_prepare(gAudioALSA.front_handle);
+ snd_pcm_write(gAudioALSA.front_handle, output_samples, num_samples<<1);
+ if((err = snd_pcm_channel_status(gAudioALSA.front_handle,
+ &status_front)) < 0) {
+ perr("snd_pcm_channel_status() failed: %s", snd_strerror(err));
+ }
+ if(status_front.underrun) {
+ perr("front write error, giving up\n");
+ }
+ }
+ */
+
+ /*
+ * remember vpts
+ */
+
+ gAudioALSA.sync_vpts = vpts;
+ gAudioALSA.sync_bytes_in_buffer = gAudioALSA.bytes_in_buffer;
+
+ /*
+ * step values
+ */
+ gAudioALSA.bytes_in_buffer +=
+ num_output_samples * 2 * gAudioALSA.num_channels;
+
+ gAudioALSA.audio_started = 1;
+ }
+ else {
+ printf ("audio_alsa_out: audio package (vpts = %d) dropped\n", vpts);
+ gAudioALSA.sync_vpts = vpts;
+ }
+
+ gAudioALSA.last_vpts =
+ vpts + num_samples * 90000 / gAudioALSA.input_sample_rate ;
+
+}
+
+/* ------------------------------------------------------------------------- */
+/*
+ *
+ */
+static void ao_close(void) {
+ int err;
+
+ if(gAudioALSA.front_handle) {
+ if((err = snd_pcm_playback_flush(gAudioALSA.front_handle)) < 0) {
+ perr("snd_pcm_channel_flush() failed: %s\n", snd_strerror(err));
+ }
+
+ if((err = snd_pcm_close(gAudioALSA.front_handle)) < 0) {
+ perr("snd_pcm_close() failed: %s\n", snd_strerror(err));
+ }
+
+ gAudioALSA.front_handle = NULL;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/*
+ *
+ */
+static int ao_is_mode_supported (int mode) {
+
+ switch (mode) {
+
+ case AO_MODE_STEREO:
+ case AO_MODE_AC3:
+ /*case AO_MODE_MONO: FIXME */
+ return 1;
+
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+/*
+ *
+ */
+static ao_functions_t audio_alsaout = {
+ ao_is_mode_supported,
+ ao_open,
+ ao_put_samples,
+ ao_close
+};
+/* ------------------------------------------------------------------------- */
+/*
+ *
+ */
+static void sighandler(int signum) {
+}
+/* ------------------------------------------------------------------------- */
+/*
+ *
+ */
+ao_functions_t *audio_alsaout_init(void) {
+ int best_rate;
+ int devnum;
+ int err;
+ int direction = SND_PCM_OPEN_PLAYBACK;
+ int snd_default_card;
+ int snd_default_mixer_card;
+ int snd_default_mixer_device;
+ snd_pcm_info_t pcm_info;
+ snd_pcm_channel_info_t pcm_chan_info;
+ struct sigaction action;
+
+ /* Check if, at least, one card is installed */
+ if((devnum = snd_cards()) == 0) {
+ return NULL;
+ }
+ else {
+ snd_default_card = snd_defaults_card();
+ if((err = snd_card_load(snd_default_card)) < 0) {
+ perr("snd_card_load() failed: %s\n", snd_strerror(err));
+ }
+ xprintf (VERBOSE|AUDIO, "%d card(s) installed. Default = %d\n",
+ devnum, snd_default_card);
+
+ if((snd_default_mixer_card = snd_defaults_mixer_card()) < 0) {
+ perr("snd_defaults_mixer_card() failed: %s\n",
+ snd_strerror(snd_default_mixer_card));
+ }
+ xprintf (VERBOSE|AUDIO, "default mixer card = %d\n",
+ snd_default_mixer_card);
+
+ if((snd_default_mixer_device = snd_defaults_mixer_device()) < 0) {
+ perr("snd_defaults_mixer_device() failed: %s\n",
+ snd_strerror(snd_default_mixer_device));
+ }
+ xprintf (VERBOSE|AUDIO, "default mixer device = %d\n",
+ snd_default_mixer_device);
+ }
+
+ xprintf (VERBOSE|AUDIO, "Opening audio device...");
+
+ if((gAudioALSA.pcm_default_card = snd_defaults_pcm_card()) < 0) {
+ perr("There is no default pcm card.\n");
+ exit(1);
+ }
+ xprintf (VERBOSE|AUDIO, "snd_defaults_pcm_card() return %d\n",
+ gAudioALSA.pcm_default_card);
+
+ if((gAudioALSA.pcm_default_device = snd_defaults_pcm_device()) < 0) {
+ perr("There is no default pcm device.\n");
+ exit(1);
+ }
+ xprintf (VERBOSE|AUDIO, "snd_defaults_pcm_device() return %d\n",
+ gAudioALSA.pcm_default_device);
+
+ action.sa_handler = sighandler;
+ sigemptyset(&(action.sa_mask));
+ action.sa_flags = 0;
+ if(sigaction(SIGALRM, &action, NULL) != 0) {
+ perr("sigaction(SIGALRM) failed: %s\n", strerror(errno));
+ }
+ alarm(2);
+
+ if((err = snd_pcm_open(&gAudioALSA.front_handle, gAudioALSA.pcm_default_card,
+ gAudioALSA.pcm_default_device, direction)) < 0) {
+ perr("snd_pcm_open() failed: %s\n", snd_strerror(err));
+ perr(">>> Check if another program don't already use PCM <<<\n");
+ return NULL;
+ }
+
+ memset(&pcm_info, 0, sizeof(snd_pcm_info_t));
+ if((err = snd_pcm_info(gAudioALSA.front_handle, &pcm_info)) < 0) {
+ perr("snd_pcm_info() failed: %s\n", snd_strerror(err));
+ exit(1);
+ }
+
+ xprintf (VERBOSE|AUDIO, "snd_pcm_info():\n");
+ xprintf (VERBOSE|AUDIO, "---------------\n");
+ xprintf (VERBOSE|AUDIO, "type = 0x%x\n", pcm_info.type);
+ xprintf (VERBOSE|AUDIO, "flags = 0x%x\n", pcm_info.flags);
+ xprintf (VERBOSE|AUDIO, "id = '%s'\n", pcm_info.id);
+ xprintf (VERBOSE|AUDIO, "name = '%s'\n", pcm_info.name);
+ xprintf (VERBOSE|AUDIO, "playback = %d\n", pcm_info.playback);
+ xprintf (VERBOSE|AUDIO, "capture = %d\n", pcm_info.capture);
+
+ memset(&pcm_chan_info, 0, sizeof(snd_pcm_channel_info_t));
+ pcm_chan_info.channel = SND_PCM_CHANNEL_PLAYBACK;
+ if((err = snd_pcm_channel_info(gAudioALSA.front_handle,
+ &pcm_chan_info)) < 0) {
+ perr("snd_pcm_channel_info() failed: %s\n", snd_strerror(err));
+ exit(1);
+ }
+
+ best_rate = pcm_chan_info.rates;
+
+ xprintf (VERBOSE|AUDIO, "best_rate = %d\n", best_rate);
+ xprintf (VERBOSE|AUDIO, "snd_pcm_channel_info(PLAYBACK):\n");
+ xprintf (VERBOSE|AUDIO, "-------------------------------\n");
+ xprintf (VERBOSE|AUDIO, "subdevice = %d\n",
+ pcm_chan_info.subdevice);
+ xprintf (VERBOSE|AUDIO, "subname = %s\n",
+ pcm_chan_info.subname);
+ xprintf (VERBOSE|AUDIO, "channel = %d\n",
+ pcm_chan_info.channel);
+ xprintf (VERBOSE|AUDIO, "mode = %d\n",
+ pcm_chan_info.mode);
+ xprintf (VERBOSE|AUDIO, "flags = 0x%x\n",
+ pcm_chan_info.flags);
+ xprintf (VERBOSE|AUDIO, "formats = %d\n",
+ pcm_chan_info.formats);
+ xprintf (VERBOSE|AUDIO, "rates = %d\n",
+ pcm_chan_info.rates);
+ xprintf (VERBOSE|AUDIO, "min_rate = %d\n",
+ pcm_chan_info.min_rate);
+ xprintf (VERBOSE|AUDIO, "max_rate = %d\n",
+ pcm_chan_info.max_rate);
+ xprintf (VERBOSE|AUDIO, "min_voices = %d\n",
+ pcm_chan_info.min_voices);
+ xprintf (VERBOSE|AUDIO, "max_voices = %d\n",
+ pcm_chan_info.max_voices);
+ xprintf (VERBOSE|AUDIO, "buffer_size = %d\n",
+ pcm_chan_info.buffer_size);
+ xprintf (VERBOSE|AUDIO, "min_fragment_size = %d\n",
+ pcm_chan_info.min_fragment_size);
+ xprintf (VERBOSE|AUDIO, "max_fragment_size = %d\n",
+ pcm_chan_info.max_fragment_size);
+ xprintf (VERBOSE|AUDIO, "fragment_align = %d\n",
+ pcm_chan_info.fragment_align);
+ xprintf (VERBOSE|AUDIO, "fifo_size = %d\n",
+ pcm_chan_info.fifo_size);
+ xprintf (VERBOSE|AUDIO, "transfer_block_size = %d\n",
+ pcm_chan_info.transfer_block_size);
+ xprintf (VERBOSE|AUDIO, "mmap_size = %ld\n",
+ pcm_chan_info.mmap_size);
+ xprintf (VERBOSE|AUDIO, "mixer_device = %d\n",
+ pcm_chan_info.mixer_device);
+
+ snd_pcm_close (gAudioALSA.front_handle);
+ gAudioALSA.front_handle = NULL;
+
+ return &audio_alsaout;
+}
diff --git a/src/audio_out/audio_alsa_out.h b/src/audio_out/audio_alsa_out.h
new file mode 100644
index 000000000..123282262
--- /dev/null
+++ b/src/audio_out/audio_alsa_out.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: audio_alsa_out.h,v 1.1 2001/04/24 20:53:00 f1rmb Exp $
+ */
+#ifndef _AUDIO_ALSA_OUT_H_
+#define _AUDIO_ALSA_OUT_H_ 1
+
+ao_functions_t *audio_alsaout_init(void);
+
+#endif
+
diff --git a/src/audio_out/audio_esd_out.c b/src/audio_out/audio_esd_out.c
new file mode 100644
index 000000000..259364a55
--- /dev/null
+++ b/src/audio_out/audio_esd_out.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; 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 <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <esd.h>
+#include <sys/time.h>
+#include <inttypes.h>
+
+#include "xine/xine.h"
+#include "xine/monitor.h"
+#include "xine/audio_out.h"
+#include "resample.h"
+#include "xine/metronom.h"
+#include "xine/ac3.h"
+#include "xine/utils.h"
+
+#define GAP_TOLERANCE 15000
+#define MAX_MASTER_CLOCK_DIV 5000
+
+extern uint32_t xine_debug;
+
+typedef struct _audio_esd_globals {
+
+ int audio_fd;
+
+ int32_t output_sample_rate, input_sample_rate;
+ int32_t output_rate_correction;
+ double sample_rate_factor;
+ uint32_t num_channels;
+
+ uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */
+ uint32_t last_vpts; /* vpts at which last written package ends */
+
+ uint32_t sync_vpts; /* this syncpoint is used as a starting point */
+ uint32_t sync_bytes_in_buffer; /* for vpts <-> samplecount assoc */
+
+ int audio_step; /* pts per 32 768 samples (sample = #bytes/2) */
+ int32_t bytes_per_kpts; /* bytes per 1024/90000 sec */
+
+ int16_t *zero_space;
+
+ int audio_started;
+
+} audio_esd_globals_t;
+
+static audio_esd_globals_t gAudioESD;
+
+/*
+ * open the audio device for writing to
+ */
+static int ao_open(uint32_t bits, uint32_t rate, int mode)
+{
+ esd_format_t format;
+
+ printf ("audio_esd_out: ao_open rate=%d, mode=%d\n", rate, mode);
+
+ if ((mode != AO_MODE_STEREO) && (mode != AO_MODE_MONO)) {
+ printf ("ESD Driver only supports mono/stereo output modes at the moment\n");
+ return -1;
+ }
+
+ if (gAudioESD.audio_fd > -1) {
+
+ if (rate == gAudioESD.input_sample_rate)
+ return 1;
+
+ close (gAudioESD.audio_fd);
+ }
+
+ gAudioESD.input_sample_rate = rate;
+ gAudioESD.bytes_in_buffer = 0;
+ gAudioESD.last_vpts = 0;
+ gAudioESD.output_rate_correction = 0;
+ gAudioESD.sync_vpts = 0;
+ gAudioESD.sync_bytes_in_buffer = 0;
+ gAudioESD.audio_started = 0;
+
+ /*
+ * open stream to ESD server
+ */
+
+ format = ESD_STREAM | ESD_PLAY | ESD_BITS16;
+ if (mode == AO_MODE_STEREO) {
+ format |= ESD_STEREO;
+ gAudioESD.num_channels = 2;
+ } else {
+ format |= ESD_MONO;
+ gAudioESD.num_channels = 1;
+ }
+ gAudioESD.output_sample_rate = gAudioESD.input_sample_rate;
+ if (gAudioESD.output_sample_rate > 44100)
+ gAudioESD.output_sample_rate = 44100;
+
+ gAudioESD.audio_fd=esd_play_stream(format, gAudioESD.output_sample_rate, NULL, NULL);
+ if(gAudioESD.audio_fd < 0) {
+ printf("audio_esd_out: Connecting to ESD server %s: %s\n",
+ getenv("ESPEAKER"), strerror(errno));
+ return -1;
+ }
+
+ xprintf (VERBOSE|AUDIO, "audio_esd_out: %d channels\n",gAudioESD.num_channels);
+
+ gAudioESD.sample_rate_factor = (double) gAudioESD.output_sample_rate / (double) gAudioESD.input_sample_rate;
+ gAudioESD.audio_step = (uint32_t) 90000 * (uint32_t) 32768
+ / gAudioESD.input_sample_rate;
+ gAudioESD.bytes_per_kpts = gAudioESD.output_sample_rate * gAudioESD.num_channels * 2 * 1024 / 90000;
+
+ xprintf (VERBOSE|AUDIO, "audio_out : audio_step %d pts per 32768 samples\n", gAudioESD.audio_step);
+
+ metronom_set_audio_rate (gAudioESD.audio_step);
+
+ return 1;
+}
+
+static uint32_t ao_get_current_vpts (void) {
+
+ int32_t diff ;
+ uint32_t vpts ;
+
+ if (gAudioESD.audio_started)
+ diff = 0;
+ else
+ diff = gAudioESD.sync_bytes_in_buffer;
+
+ vpts = gAudioESD.sync_vpts - diff * 1024 / gAudioESD.bytes_per_kpts;
+
+// xprintf (AUDIO|VERBOSE,"audio_esd_out: get_current_vpts pos=%d diff=%d vpts=%d sync_vpts=%d\n",
+// pos, diff, vpts, gAudioESD.sync_vpts);
+
+ return vpts;
+}
+
+static void ao_fill_gap (uint32_t pts_len) {
+
+ int num_bytes = pts_len * gAudioESD.bytes_per_kpts / 1024;
+
+ num_bytes = (num_bytes / 4) * 4;
+
+ printf ("audio_esd_out: inserting %d 0-bytes to fill a gap of %d pts\n",num_bytes, pts_len);
+
+ gAudioESD.bytes_in_buffer += num_bytes;
+
+ while (num_bytes>0) {
+ if (num_bytes>8192) {
+ write(gAudioESD.audio_fd, gAudioESD.zero_space, 8192);
+ num_bytes -= 8192;
+ } else {
+ write(gAudioESD.audio_fd, gAudioESD.zero_space, num_bytes);
+ num_bytes = 0;
+ }
+ }
+
+ gAudioESD.last_vpts += pts_len;
+}
+
+static void ao_write_audio_data(int16_t* output_samples, uint32_t num_samples,
+ uint32_t pts_)
+{
+
+ uint32_t vpts,
+ audio_vpts,
+ master_vpts;
+ int32_t diff, gap;
+ int bDropPackage;
+ uint16_t sample_buffer[8192];
+
+
+ if (gAudioESD.audio_fd<0)
+ return;
+
+ vpts = metronom_got_audio_samples (pts_, num_samples);
+
+ xprintf (VERBOSE|AUDIO, "audio_esd_out: got %d samples, vpts=%d, last_vpts=%d\n",
+ num_samples, vpts, gAudioESD.last_vpts);
+
+ /*
+ * check if these samples "fit" in the audio output buffer
+ * or do we have an audio "gap" here?
+ */
+
+ gap = vpts - gAudioESD.last_vpts ;
+
+ /*
+ printf ("audio_esd_out: gap = %d - %d + %d = %d\n",
+ vpts, gAudioESD.last_vpts, diff, gap);
+ */
+
+ bDropPackage = 0;
+
+ if (gap>GAP_TOLERANCE) {
+ ao_fill_gap (gap);
+ } else if (gap<-GAP_TOLERANCE) {
+ bDropPackage = 1;
+ }
+
+ /*
+ * sync on master clock
+ */
+
+ audio_vpts = ao_get_current_vpts () ;
+ master_vpts = metronom_get_current_time ();
+ diff = audio_vpts - master_vpts;
+
+ xprintf (AUDIO|VERBOSE, "audio_esd_out: syncing on master clock: audio_vpts=%d master_vpts=%d\n",
+ audio_vpts, master_vpts);
+ /*
+ printf ("audio_esd_out: audio_vpts=%d <=> master_vpts=%d (diff=%d)\n",
+ audio_vpts, master_vpts, diff);
+ */
+
+ /*
+ * adjust master clock
+ */
+
+ if (abs(diff)>MAX_MASTER_CLOCK_DIV) {
+ printf ("master clock adjust time %d -> %d (diff: %d)\n", master_vpts, audio_vpts, diff);
+ metronom_adjust_clock (audio_vpts);
+ }
+
+ /*
+ * resample and output samples
+ */
+
+ if (!bDropPackage) {
+ int num_output_samples = num_samples * (gAudioESD.output_sample_rate + gAudioESD.output_rate_correction) / gAudioESD.input_sample_rate;
+
+
+ audio_out_resample_stereo (output_samples, num_samples,
+ sample_buffer, num_output_samples);
+
+ write(gAudioESD.audio_fd, sample_buffer, num_output_samples * 2 * gAudioESD.num_channels);
+
+ xprintf (AUDIO|VERBOSE, "audio_esd_out :audio package written\n");
+
+ /*
+ * remember vpts
+ */
+
+ gAudioESD.sync_vpts = vpts;
+ gAudioESD.sync_bytes_in_buffer = gAudioESD.bytes_in_buffer;
+
+ /*
+ * step values
+ */
+
+ gAudioESD.bytes_in_buffer += num_output_samples * 2 * gAudioESD.num_channels;
+ gAudioESD.audio_started = 1;
+ } else {
+ printf ("audio_esd_out: audio package (vpts = %d) dropped\n", vpts);
+ gAudioESD.sync_vpts = vpts;
+ }
+
+ gAudioESD.last_vpts = vpts + num_samples * 90000 / gAudioESD.input_sample_rate ;
+}
+
+
+static void ao_close(void)
+{
+ close(gAudioESD.audio_fd);
+ gAudioESD.audio_fd = -1;
+}
+
+static int ao_is_mode_supported (int mode) {
+ return ((mode == AO_MODE_STEREO) || (mode == AO_MODE_MONO));
+}
+
+static ao_functions_t audio_esdout = {
+ ao_is_mode_supported,
+ ao_open,
+ ao_write_audio_data,
+ ao_close,
+};
+
+
+ao_functions_t *audio_esdout_init (void)
+{
+ int audio_fd;
+
+ /*
+ * open stream to ESD server
+ */
+
+ xprintf(VERBOSE|AUDIO, "Connecting to ESD server...");
+ audio_fd = esd_open_sound(NULL);
+
+ if(audio_fd < 0)
+ {
+ char *server = getenv("ESPEAKER");
+
+ // print a message so the user knows why ESD failed
+ printf("Can't connect to %s ESD server: %s\n",
+ server ? server : "local", strerror(errno));
+
+ return NULL;
+ } // else
+// xprintf(VERBOSE|AUDIO, " %s\n", gAudioESD.audio_dev);
+
+ close(audio_fd);
+
+ gAudioESD.output_sample_rate = 0;
+ gAudioESD.zero_space = xmalloc (8192);
+
+ return &audio_esdout;
+}
diff --git a/src/audio_out/audio_esd_out.h b/src/audio_out/audio_esd_out.h
new file mode 100644
index 000000000..a98dcc34f
--- /dev/null
+++ b/src/audio_out/audio_esd_out.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef _AUDIO_ESD_OUT_H_
+#define _AUDIO_ESD_OUT_H_ 1
+
+ao_functions_t *audio_esdout_init(void);
+
+#endif
diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c
new file mode 100644
index 000000000..18d11ff5d
--- /dev/null
+++ b/src/audio_out/audio_oss_out.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: audio_oss_out.c,v 1.1 2001/04/24 20:53:00 f1rmb Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#if defined(__OpenBSD__)
+#include <soundcard.h>
+#elif defined(__FreeBSD__)
+#include <machine/soundcard.h>
+#else
+#include <sys/soundcard.h>
+#endif
+#include <sys/ioctl.h>
+#include <inttypes.h>
+
+#include "xine/xine.h"
+#include "xine/monitor.h"
+#include "xine/audio_out.h"
+#include "resample.h"
+#include "xine/metronom.h"
+#include "xine/ac3.h"
+#include "xine/utils.h"
+
+#define AUDIO_NUM_FRAGMENTS 15
+#define AUDIO_FRAGMENT_SIZE 8192
+
+#define GAP_TOLERANCE 15000
+#define MAX_MASTER_CLOCK_DIV 5000
+
+extern uint32_t xine_debug;
+
+#define DSP_TEMPLATE "/dev/dsp%d"
+
+typedef struct _audio_oss_globals {
+
+ char audio_dev[20];
+ int audio_fd;
+
+ int32_t output_sample_rate, input_sample_rate;
+ int32_t output_rate_correction;
+ double sample_rate_factor;
+ uint32_t num_channels;
+
+ uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */
+ uint32_t last_vpts; /* vpts at which last written package ends */
+
+ uint32_t sync_vpts; /* this syncpoint is used as a starting point */
+ uint32_t sync_bytes_in_buffer; /* for vpts <-> samplecount assoc */
+
+ int audio_step; /* pts per 32 768 samples (sample = #bytes/2) */
+ int32_t bytes_per_kpts; /* bytes per 1024/90000 sec */
+
+ int16_t *zero_space;
+
+ int audio_started;
+
+} audio_oss_globals_t;
+
+static audio_oss_globals_t gAudioOSS;
+
+/*
+ * open the audio device for writing to
+ */
+static int ao_open(uint32_t bits, uint32_t rate, int mode)
+{
+ int tmp;
+ int fsize;
+
+ printf ("audio_oss_out: ao_open rate=%d, mode=%d\n", rate, mode);
+
+ if ((mode != AO_MODE_STEREO) && (mode != AO_MODE_MONO)) {
+ printf ("OSS Driver only supports mono/stereo output modes at the moment\n");
+ return -1;
+ }
+
+ if (gAudioOSS.audio_fd > -1) {
+
+ if (rate == gAudioOSS.input_sample_rate)
+ return 1;
+
+ close (gAudioOSS.audio_fd);
+ }
+
+ gAudioOSS.input_sample_rate = rate;
+ gAudioOSS.bytes_in_buffer = 0;
+ gAudioOSS.last_vpts = 0;
+ gAudioOSS.output_rate_correction = 0;
+ gAudioOSS.sync_vpts = 0;
+ gAudioOSS.sync_bytes_in_buffer = 0;
+ gAudioOSS.audio_started = 0;
+
+ /*
+ * open audio device
+ */
+
+ gAudioOSS.audio_fd=open(gAudioOSS.audio_dev,O_WRONLY|O_NDELAY);
+ if(gAudioOSS.audio_fd < 0) {
+ printf("audio_oss_out: Opening audio device %s: %s\n",
+ gAudioOSS.audio_dev, strerror(errno));
+ return -1;
+ }
+
+ /* We wanted non blocking open but now put it back to normal */
+ fcntl(gAudioOSS.audio_fd, F_SETFL, fcntl(gAudioOSS.audio_fd, F_GETFL)&~FNDELAY);
+
+ /*
+ * configure audio device
+ */
+
+ tmp = (mode == AO_MODE_STEREO) ? 1 : 0;
+ ioctl(gAudioOSS.audio_fd,SNDCTL_DSP_STEREO,&tmp);
+
+ gAudioOSS.num_channels = tmp+1;
+ xprintf (VERBOSE|AUDIO, "audio_oss_out: %d channels\n",gAudioOSS.num_channels);
+
+ tmp = bits;
+ ioctl(gAudioOSS.audio_fd,SNDCTL_DSP_SAMPLESIZE,&tmp);
+
+ tmp = gAudioOSS.input_sample_rate;
+ ioctl(gAudioOSS.audio_fd,SNDCTL_DSP_SPEED, &tmp);
+ gAudioOSS.output_sample_rate = tmp;
+
+ xprintf (VERBOSE|AUDIO, "audio_oss_out: audio rate : %d requested, %d provided by device/sec\n",
+ gAudioOSS.input_sample_rate, gAudioOSS.output_sample_rate);
+
+ gAudioOSS.sample_rate_factor = (double) gAudioOSS.output_sample_rate / (double) gAudioOSS.input_sample_rate;
+ gAudioOSS.audio_step = (uint32_t) 90000 * (uint32_t) 32768
+ / gAudioOSS.input_sample_rate;
+ gAudioOSS.bytes_per_kpts = gAudioOSS.output_sample_rate * gAudioOSS.num_channels * 2 * 1024 / 90000;
+
+ xprintf (VERBOSE|AUDIO, "audio_out : audio_step %d pts per 32768 samples\n", gAudioOSS.audio_step);
+
+ metronom_set_audio_rate (gAudioOSS.audio_step);
+
+ /*
+ * audio buffer size handling
+ */
+
+ tmp=0 ;
+ fsize = AUDIO_FRAGMENT_SIZE;
+ while (fsize>0) {
+ fsize /=2;
+ tmp++;
+ }
+ tmp--;
+
+ tmp = (AUDIO_NUM_FRAGMENTS << 16) | tmp ;
+
+ xprintf (VERBOSE|AUDIO, "Audio buffer fragment info : %x\n",tmp);
+
+ ioctl(gAudioOSS.audio_fd,SNDCTL_DSP_SETFRAGMENT,&tmp);
+
+
+ return 1;
+}
+
+static uint32_t ao_get_current_vpts (void) {
+
+ int pos ;
+ int32_t diff ;
+ uint32_t vpts ;
+
+ count_info info;
+
+ if (gAudioOSS.audio_started) {
+ ioctl (gAudioOSS.audio_fd, SNDCTL_DSP_GETOPTR, &info);
+
+ pos = info.bytes;
+
+ } else
+ pos = 0;
+
+ diff = gAudioOSS.sync_bytes_in_buffer - pos;
+
+ vpts = gAudioOSS.sync_vpts - diff * 1024 / gAudioOSS.bytes_per_kpts;
+
+ xprintf (AUDIO|VERBOSE,"audio_oss_out: get_current_vpts pos=%d diff=%d vpts=%d sync_vpts=%d\n",
+ pos, diff, vpts, gAudioOSS.sync_vpts);
+
+ return vpts;
+}
+
+static void ao_fill_gap (uint32_t pts_len) {
+
+ int num_bytes = pts_len * gAudioOSS.bytes_per_kpts / 1024;
+
+ num_bytes = (num_bytes / 4) * 4;
+
+ printf ("audio_oss_out: inserting %d 0-bytes to fill a gap of %d pts\n",num_bytes, pts_len);
+
+ gAudioOSS.bytes_in_buffer += num_bytes;
+
+ while (num_bytes>0) {
+ if (num_bytes>8192) {
+ write(gAudioOSS.audio_fd, gAudioOSS.zero_space, 8192);
+ num_bytes -= 8192;
+ } else {
+ write(gAudioOSS.audio_fd, gAudioOSS.zero_space, num_bytes);
+ num_bytes = 0;
+ }
+ }
+
+ gAudioOSS.last_vpts += pts_len;
+}
+
+static void ao_write_audio_data(int16_t* output_samples, uint32_t num_samples,
+ uint32_t pts_)
+{
+
+ uint32_t vpts,
+ audio_vpts,
+ master_vpts;
+ int32_t diff, gap;
+ int bDropPackage;
+ uint16_t sample_buffer[8192];
+
+
+ if (gAudioOSS.audio_fd<0)
+ return;
+
+ vpts = metronom_got_audio_samples (pts_, num_samples);
+
+ xprintf (VERBOSE|AUDIO, "audio_oss_out: got %d samples, vpts=%d, last_vpts=%d\n",
+ num_samples, vpts, gAudioOSS.last_vpts);
+
+ /*
+ * check if these samples "fit" in the audio output buffer
+ * or do we have an audio "gap" here?
+ */
+
+ gap = vpts - gAudioOSS.last_vpts ;
+
+ /*
+ printf ("audio_oss_out: gap = %d - %d + %d = %d\n",
+ vpts, gAudioOSS.last_vpts, diff, gap);
+ */
+
+ bDropPackage = 0;
+
+ if (gap>GAP_TOLERANCE) {
+ ao_fill_gap (gap);
+ } else if (gap<-GAP_TOLERANCE) {
+ bDropPackage = 1;
+ }
+
+ /*
+ * sync on master clock
+ */
+
+ audio_vpts = ao_get_current_vpts () ;
+ master_vpts = metronom_get_current_time ();
+ diff = audio_vpts - master_vpts;
+
+ xprintf (AUDIO|VERBOSE, "audio_oss_out: syncing on master clock: audio_vpts=%d master_vpts=%d\n",
+ audio_vpts, master_vpts);
+ /*
+ printf ("audio_oss_out: audio_vpts=%d <=> master_vpts=%d (diff=%d)\n",
+ audio_vpts, master_vpts, diff);
+ */
+ /*
+ * method 1 : resampling
+ */
+
+ /*
+ if (abs(diff)>5000) {
+
+ if (diff>5000) {
+ ao_fill_gap (diff);
+ } else if (diff<-5000) {
+ bDropPackage = 1;
+ }
+
+ } else if (abs(diff)>1000) {
+ gAudioOSS.output_rate_correction = diff/10 ;
+
+ printf ("audio_oss_out: diff = %d => rate correction : %d\n", diff, gAudioOSS.output_rate_correction);
+
+ if ( gAudioOSS.output_rate_correction < -500)
+ gAudioOSS.output_rate_correction = -500;
+ else if ( gAudioOSS.output_rate_correction > 500)
+ gAudioOSS.output_rate_correction = 500;
+ }
+ */
+
+ /*
+ * method 2: adjust master clock
+ */
+
+
+ if (abs(diff)>MAX_MASTER_CLOCK_DIV) {
+ printf ("master clock adjust time %d -> %d (diff: %d)\n", master_vpts, audio_vpts, diff);
+ metronom_adjust_clock (audio_vpts);
+ }
+
+
+ /*
+ * resample and output samples
+ */
+
+ if (!bDropPackage) {
+ int num_output_samples = num_samples * (gAudioOSS.output_sample_rate + gAudioOSS.output_rate_correction) / gAudioOSS.input_sample_rate;
+
+
+ audio_out_resample_stereo (output_samples, num_samples,
+ sample_buffer, num_output_samples);
+
+ write(gAudioOSS.audio_fd, sample_buffer, num_output_samples * 2 * gAudioOSS.num_channels);
+
+ xprintf (AUDIO|VERBOSE, "audio_oss_out :audio package written\n");
+
+ /*
+ * remember vpts
+ */
+
+ gAudioOSS.sync_vpts = vpts;
+ gAudioOSS.sync_bytes_in_buffer = gAudioOSS.bytes_in_buffer;
+
+ /*
+ * step values
+ */
+
+ gAudioOSS.bytes_in_buffer += num_output_samples * 2 * gAudioOSS.num_channels;
+ gAudioOSS.audio_started = 1;
+ } else {
+ printf ("audio_oss_out: audio package (vpts = %d) dropped\n", vpts);
+ gAudioOSS.sync_vpts = vpts;
+ }
+
+ gAudioOSS.last_vpts = vpts + num_samples * 90000 / gAudioOSS.input_sample_rate ;
+}
+
+
+static void ao_close(void)
+{
+ close(gAudioOSS.audio_fd);
+ gAudioOSS.audio_fd = -1;
+}
+
+static int ao_is_mode_supported (int mode) {
+ return ((mode == AO_MODE_STEREO) || (mode == AO_MODE_MONO));
+}
+
+static ao_functions_t audio_ossout = {
+ ao_is_mode_supported,
+ ao_open,
+ ao_write_audio_data,
+ ao_close,
+};
+
+
+ao_functions_t *audio_ossout_init (void)
+{
+ int caps;
+ char devname[] = "/dev/dsp\0\0\0";
+ int best_rate;
+ int rate ;
+ int devnum;
+ int audio_fd;
+
+ /*
+ * find best device driver/channel
+ */
+
+ xprintf (VERBOSE|AUDIO, "Opening audio device...");
+ devnum = 0;
+ best_rate = 0;
+ while (devnum<16) {
+ audio_fd=open(devname,O_WRONLY|O_NDELAY);
+
+ if (audio_fd>0) {
+
+ /* test bitrate capability */
+
+ rate = 48000;
+ ioctl(audio_fd,SNDCTL_DSP_SPEED, &rate);
+ if (rate>best_rate) {
+ strncpy (gAudioOSS.audio_dev, devname, 19);
+ best_rate = rate;
+ }
+
+ close (audio_fd);
+ }
+
+ sprintf(devname, DSP_TEMPLATE, devnum);
+ devnum++;
+ }
+
+ /*
+ * open that device
+ */
+
+ audio_fd=open(gAudioOSS.audio_dev, O_WRONLY|O_NDELAY);
+
+ if(audio_fd < 0)
+ {
+ xprintf(VERBOSE|AUDIO, "%s: Opening audio device %s\n",
+ strerror(errno), gAudioOSS.audio_dev);
+
+ return NULL;
+
+ } else
+ xprintf (VERBOSE|AUDIO, " %s\n", gAudioOSS.audio_dev);
+
+ ioctl (audio_fd, SNDCTL_DSP_GETCAPS, &caps);
+
+ if ((caps & DSP_CAP_REALTIME) > 0) {
+ xprintf (VERBOSE|AUDIO, "audio_out : realtime check: passed :-)\n");
+ } else {
+ xprintf (VERBOSE|AUDIO, "audio_out : realtime check: *FAILED* :-(((((\n\n");
+ }
+
+ if ((caps & DSP_CAP_TRIGGER) > 0) {
+ xprintf (VERBOSE|AUDIO, "audio_out : trigger check : passed :-)\n");
+ } else {
+ xprintf (VERBOSE|AUDIO, "audio_out : trigger check : *FAILED* :-(((((\n");
+ }
+
+ close (audio_fd);
+
+ gAudioOSS.output_sample_rate = 0;
+
+ gAudioOSS.zero_space = xmalloc (8192);
+
+ return &audio_ossout;
+}
diff --git a/src/audio_out/audio_oss_out.h b/src/audio_out/audio_oss_out.h
new file mode 100644
index 000000000..2618acbf9
--- /dev/null
+++ b/src/audio_out/audio_oss_out.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: audio_oss_out.h,v 1.1 2001/04/24 20:53:00 f1rmb Exp $
+ */
+#ifndef _AUDIO_OSS_OUT_H_
+#define _AUDIO_OSS_OUT_H_ 1
+
+ao_functions_t *audio_ossout_init(void);
+
+#endif
diff --git a/src/audio_out/resample.c b/src/audio_out/resample.c
new file mode 100644
index 000000000..9f464b276
--- /dev/null
+++ b/src/audio_out/resample.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: resample.c,v 1.1 2001/04/24 20:53:00 f1rmb Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <inttypes.h>
+
+/* contributed by paul flinders */
+
+void audio_out_resample_stereo(int16_t* input_samples, uint32_t in_samples,
+ int16_t* output_samples, uint32_t out_samples)
+{
+ int osample;
+ /* 16+16 fixed point math */
+ uint32_t isample = 0;
+ uint32_t istep = (in_samples << 16)/out_samples;
+
+#ifdef VERBOSE
+ printf ("Audio : resample %d samples to %d\n",
+ in_samples, out_samples);
+#endif
+
+ for (osample = 0; osample < out_samples - 1; osample++) {
+ int s1;
+ int s2;
+ int16_t os;
+ uint32_t t = isample&0xffff;
+
+ /* don't "optimize" the (isample >> 16)*2 to (isample >> 15) */
+ s1 = input_samples[(isample >> 16)*2];
+ s2 = input_samples[(isample >> 16)*2+2];
+
+ os = (s1 * (0x10000-t)+ s2 * t) >> 16;
+ output_samples[osample * 2] = os;
+
+ s1 = input_samples[(isample >> 16)*2+1];
+ s2 = input_samples[(isample >> 16)*2+3];
+
+ os = (s1 * (0x10000-t)+ s2 * t) >> 16;
+ output_samples[(osample * 2 )+1] = os;
+ isample += istep;
+ }
+ output_samples[out_samples*2-2] = input_samples[in_samples*2-2];
+ output_samples[out_samples*2-1] = input_samples[in_samples*2-1];
+}
+
diff --git a/src/audio_out/resample.h b/src/audio_out/resample.h
new file mode 100644
index 000000000..11c9e4a45
--- /dev/null
+++ b/src/audio_out/resample.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: resample.h,v 1.1 2001/04/24 20:53:00 f1rmb Exp $
+ *
+ * utilitiy functions for audio drivers
+ *
+ * FIXME: not all of them are implemented yet
+ */
+
+#ifndef HAVE_RESAMPLE_H
+#define HAVE_RESAMPLE_H
+
+void audio_out_resample_stereo(int16_t* input_samples, uint32_t in_samples,
+ int16_t* output_samples, uint32_t out_samples);
+
+void audio_out_resample_mono(int16_t* input_samples, uint32_t in_samples,
+ int16_t* output_samples, uint32_t out_samples);
+
+void audio_out_resample_4channel(int16_t* input_samples, uint32_t in_samples,
+ int16_t* output_samples, uint32_t out_samples);
+
+void audio_out_resample_5channel(int16_t* input_samples, uint32_t in_samples,
+ int16_t* output_samples, uint32_t out_samples);
+
+#endif
diff --git a/src/video_out/Makefile.am b/src/video_out/Makefile.am
new file mode 100644
index 000000000..8d0c37c20
--- /dev/null
+++ b/src/video_out/Makefile.am
@@ -0,0 +1,41 @@
+CFLAGS = @GLOBAL_CFLAGS@ @X_CFLAGS@ -DXINE_COMPILE
+
+if HAVE_X11
+## xshm and syncfb should be fixed first ;-)
+## xshm_module = xineplug_vo_out_xshm.la
+## syncfb_module = xineplug_vo_out_syncfb.la
+if HAVE_XV
+xv_module = xineplug_vo_out_xv.la
+endif
+endif
+
+##
+# IMPORTANT:
+# ---------
+# All of xine video out plugins should be named like the
+# scheme "xineplug_vo_out_"
+#
+lib_LTLIBRARIES = $(xv_module) ## $(xshm_module) $(syncfb_module)
+
+xineplug_vo_out_xv_la_SOURCES = yuv2rgb.c yuv2rgb_mmx.c video_out_xv.c
+xineplug_vo_out_xv_la_LDFLAGS = -avoid-version -module
+
+##xineplug_vo_out_xshm_la_SOURCES = yuv2rgb.c yuv2rgb_mmx.c video_out_xshm.c
+##xineplug_vo_out_xshm_la_LDFLAGS = -avoid-version -module
+
+##xineplug_vo_out_syncfb_la_SOURCES = yuv2rgb.c yuv2rgb_mmx.c video_out_syncfb.c
+##xineplug_vo_out_syncfb_la_LDFLAGS = -avoid-version -module
+
+noinst_HEADERS = yuv2rgb.h video_out_syncfb.h
+
+
+debug:
+ $(MAKE) CFLAGS="$(DEBUG_CFLAGS)"
+
+mostlyclean-generic:
+ -rm -f *~ \#* .*~ .\#*
+
+maintainer-clean-generic:
+ -@echo "This command is intended for maintainers to use;"
+ -@echo "it deletes files that may require special tools to rebuild."
+ -rm -f Makefile.in
diff --git a/src/video_out/video_out_syncfb.c b/src/video_out/video_out_syncfb.c
new file mode 100644
index 000000000..2d99f3216
--- /dev/null
+++ b/src/video_out/video_out_syncfb.c
@@ -0,0 +1,849 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: video_out_syncfb.c,v 1.1 2001/04/24 20:53:00 f1rmb Exp $
+ *
+ * video_out_syncfb.c, Matrox G400 video extension interface for xine
+ *
+ * based on video_out_mga code from
+ * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * xine-specific code by Joachim Koenig <joachim.koenig@gmx.net>
+ * Underlaying window by Matthias Dahl <matthew2k@web.de>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+
+#include <X11/Xutil.h>
+
+#include "video_out.h"
+#include "video_out_syncfb.h"
+
+#include "monitor.h"
+#include "configfile.h"
+
+#define MWM_HINTS_DECORATIONS (1L << 1)
+#define PROP_MWM_HINTS_ELEMENTS 5
+typedef struct _mwmhints {
+ uint32_t flags;
+ uint32_t functions;
+ uint32_t decorations;
+ int32_t input_mode;
+ uint32_t status;
+} MWMHints;
+
+Display *lDisplay;
+extern Display *gDisplay;
+extern Window gVideoWin;
+extern Pixmap gXineLogo;
+extern int gXineLogoWidth, gXineLogoHeight;
+
+extern uint32_t xine_debug;
+
+
+
+typedef struct _display {
+ int width;
+ int height;
+ int depth;
+ int default_screen;
+} display;
+
+typedef struct _window {
+ char title[20];
+
+ Window clasped_window;
+ int visibility;
+} window;
+
+typedef struct _mga_globals {
+ syncfb_config_t mga_vid_config;
+ syncfb_capability_t caps;
+ syncfb_buffer_info_t bufinfo;
+ syncfb_param_t param;
+ uint8_t *vid_data, *frame0, *frame1;
+ int next_frame;
+ int fd;
+ uint32_t bespitch;
+
+ int bFullscreen;
+ int bIsFullscreen;
+ int image_width;
+ int image_height;
+ int image_xoff;
+ int image_yoff;
+ int orig_width; /* image size correct. by ratio */
+ int orig_height;
+ int dest_width;
+ int dest_height;
+ int fourcc_format;
+
+ uint32_t ratio;
+ int user_ratio, user_ratio_changed;
+
+// XvImage *cur_image;
+
+ /*
+ * misc (read: fun ;))
+ */
+ int bLogoMode;
+
+ int bright_min, bright_current, bright_max;
+ int cont_min, cont_current, cont_max;
+
+ int overlay_state;
+
+} mga_globals;
+
+mga_globals _mga_priv;
+display _display;
+window _window;
+
+int nLocks;
+
+
+
+static int _mga_write_frame_g400 (uint8_t *src[])
+{
+ uint8_t *dest;
+ int h;
+ uint8_t *y = src[0];
+ uint8_t *cb = src[1];
+ uint8_t *cr = src[2];
+
+ dest = _mga_priv.vid_data;
+
+ if (_mga_priv.fourcc_format == IMGFMT_YUY2) {
+ for (h=0; h < _mga_priv.mga_vid_config.src_height; h++) {
+ memcpy(dest, y, _mga_priv.mga_vid_config.src_width*2);
+ y += _mga_priv.mga_vid_config.src_width*2;
+ dest += _mga_priv.bespitch*2;
+ }
+ return 0;
+ }
+
+
+ for (h=0; h < _mga_priv.mga_vid_config.src_height; h++) {
+ memcpy(dest, y, _mga_priv.mga_vid_config.src_width);
+ y += _mga_priv.mga_vid_config.src_width;
+ dest += _mga_priv.bespitch;
+ }
+
+
+ for (h=0; h < _mga_priv.mga_vid_config.src_height/2; h++) {
+ memcpy(dest, cb, _mga_priv.mga_vid_config.src_width/2);
+ cb += _mga_priv.mga_vid_config.src_width/2;
+ dest += _mga_priv.bespitch/2;
+ }
+
+ dest = _mga_priv.vid_data + _mga_priv.bespitch * _mga_priv.mga_vid_config.src_height * 3 / 2;
+
+ for (h=0; h < _mga_priv.mga_vid_config.src_height/2; h++) {
+ memcpy(dest, cr, _mga_priv.mga_vid_config.src_width/2);
+ cr += _mga_priv.mga_vid_config.src_width/2;
+ dest += _mga_priv.bespitch/2;
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+static int get_capabilities_mga () {
+ return VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_CONTRAST | VO_CAP_BRIGHTNESS;
+}
+
+
+static void setup_window_mga () {
+ int ww=0, wh=0;
+ float aspect;
+
+ XWindowAttributes wattr;
+
+ Atom prop;
+ MWMHints mwmhints;
+
+ XGetWindowAttributes(lDisplay, DefaultRootWindow(lDisplay), &wattr);
+
+ _display.width = wattr.width;
+ _display.height = wattr.height;
+ _display.depth = wattr.depth;
+
+ ww = _display.width ;
+ wh = _display.height;
+
+xprintf(VERBOSE|VIDEO,"setup_window_mga: unscaled size should be %d x %d \n",_mga_priv.orig_width,_mga_priv.orig_height);
+printf("setup_window_mga: unscaled size should be %d x %d \n",_mga_priv.orig_width,_mga_priv.orig_height);
+
+ if (_mga_priv.bFullscreen) {
+
+ /*
+ * zoom to fullscreen
+ */
+
+ if (_mga_priv.orig_width != ww) {
+ aspect = (float) _mga_priv.orig_width / (float) _mga_priv.orig_height ;
+
+ _mga_priv.dest_width = ww;
+ _mga_priv.dest_height = ww / aspect;
+
+ if (_mga_priv.dest_height > wh) {
+
+ _mga_priv.dest_width = wh * aspect;
+ _mga_priv.dest_height = wh;
+ }
+
+ } else {
+
+ _mga_priv.dest_width = _mga_priv.orig_width ;
+ _mga_priv.dest_height = _mga_priv.orig_height ;
+
+ }
+ _mga_priv.image_xoff = ( ww - _mga_priv.dest_width) / 2;
+ _mga_priv.image_yoff = ( wh - _mga_priv.dest_height) / 2;
+
+
+ _mga_priv.bIsFullscreen = 1;
+
+
+ } else {
+
+ /*
+ * zoom to mpeg1 to double size
+ */
+
+// if (_mga_priv.orig_width < 600) {
+// _mga_priv.dest_width = _mga_priv.orig_width *2;
+// _mga_priv.dest_height = _mga_priv.orig_height *2;
+// } else {
+
+ if (_mga_priv.orig_width > ww) {
+ aspect = (float) _mga_priv.orig_width / (float) _mga_priv.orig_height ;
+
+ _mga_priv.dest_width = ww;
+ _mga_priv.dest_height = ww / aspect;
+
+ if (_mga_priv.dest_height > wh) {
+ _mga_priv.dest_width = wh * aspect;
+ _mga_priv.dest_height = wh;
+ }
+
+ } else {
+ _mga_priv.dest_width = _mga_priv.orig_width ;
+ _mga_priv.dest_height = _mga_priv.orig_height ;
+ }
+// }
+
+ _mga_priv.bIsFullscreen = 0;
+
+ _mga_priv.image_xoff = ( ww - _mga_priv.dest_width) / 2;
+ _mga_priv.image_yoff = ( wh - _mga_priv.dest_height) / 2;
+
+ }
+ xprintf(VERBOSE|VIDEO,"Calculated size should be %d x %d xoff %d yoff %d Display Is %d x %d\n",_mga_priv.dest_width,_mga_priv.dest_height,_mga_priv.image_xoff,_mga_priv.image_yoff,ww,wh);
+ printf("Calculated size should be %d x %d xoff %d yoff %d Display Is %d x %d\n",_mga_priv.dest_width,_mga_priv.dest_height,_mga_priv.image_xoff,_mga_priv.image_yoff,ww,wh);
+
+ if (ioctl(_mga_priv.fd,SYNCFB_GET_CAPS,&_mga_priv.caps)) perror("Error in config ioctl");
+ xprintf(VERBOSE|VIDEO,"Syncfb device name is '%s'\n", _mga_priv.caps.name);
+ xprintf(VERBOSE|VIDEO,"Memory size is %ld \n", _mga_priv.caps.memory_size);
+
+ if (ioctl(_mga_priv.fd,SYNCFB_GET_CONFIG,&_mga_priv.mga_vid_config))
+ printf("Error in get_config ioctl\n");
+
+ _mga_priv.mga_vid_config.fb_screen_size = _display.width * _display.height * (_display.depth/8); // maybe wrong if depth = 15 (?)
+ _mga_priv.mga_vid_config.src_width = _mga_priv.image_width;
+ _mga_priv.mga_vid_config.src_height= _mga_priv.image_height;
+ _mga_priv.bespitch = (_mga_priv.image_width + 31) & ~31;
+
+ switch (_mga_priv.fourcc_format) {
+ case IMGFMT_YV12:
+ _mga_priv.mga_vid_config.src_palette = VIDEO_PALETTE_YUV420P3;
+ break;
+ case IMGFMT_YUY2:
+ _mga_priv.mga_vid_config.src_palette = VIDEO_PALETTE_YUYV;
+ break;
+ default:
+ _mga_priv.mga_vid_config.src_palette = VIDEO_PALETTE_YUV420P3;
+ break;
+ }
+ _mga_priv.mga_vid_config.image_width = _mga_priv.dest_width;
+ _mga_priv.mga_vid_config.image_height= _mga_priv.dest_height;
+ _mga_priv.mga_vid_config.syncfb_mode = SYNCFB_FEATURE_BLOCK_REQUEST | SYNCFB_FEATURE_SCALE_H | SYNCFB_FEATURE_SCALE_V | SYNCFB_FEATURE_CROP ; /* | SYNCFB_FEATURE_DEINTERLACE; */
+ _mga_priv.mga_vid_config.image_xorg= _mga_priv.image_xoff;
+ _mga_priv.mga_vid_config.image_yorg= _mga_priv.image_yoff;
+
+ _mga_priv.mga_vid_config.src_crop_top = 0;
+ _mga_priv.mga_vid_config.src_crop_bot = 0;
+
+#ifdef CINEMODE
+ _mga_priv.mga_vid_config.default_repeat = 3;
+#else
+ _mga_priv.mga_vid_config.default_repeat = 2;
+#endif
+
+ if (ioctl(_mga_priv.fd,SYNCFB_SET_CONFIG,&_mga_priv.mga_vid_config))
+ xprintf(VERBOSE|VIDEO,"Error in set_config ioctl\n");
+ if (_mga_priv.bLogoMode) {
+ if (ioctl(_mga_priv.fd,SYNCFB_OFF)) {
+ xprintf(VERBOSE|VIDEO,"Error in OFF ioctl\n");
+ }
+ else
+ _mga_priv.overlay_state = 0;
+ }
+
+// if (ioctl(_mga_priv.fd,SYNCFB_ON))
+// xprintf(VERBOSE|VIDEO,"Error in ON ioctl\n");
+
+ // create a simple window without anything. Just make overlay clickable. :)
+ if (!_window.clasped_window) {
+ _window.clasped_window = XCreateSimpleWindow(lDisplay, RootWindow(lDisplay, _display.default_screen), 0, 0, _mga_priv.dest_width, _mga_priv.dest_height, 0, 0, 0);
+ gVideoWin = _window.clasped_window;
+
+ // turn off all borders etc. (taken from the Xv plugin)
+ prop = XInternAtom(lDisplay, "_MOTIF_WM_HINTS", False);
+ mwmhints.flags = MWM_HINTS_DECORATIONS;
+ mwmhints.decorations = 0;
+ XChangeProperty(lDisplay, gVideoWin, prop, prop, 32,
+ PropModeReplace, (unsigned char *) &mwmhints,
+ PROP_MWM_HINTS_ELEMENTS);
+ XSetTransientForHint(lDisplay, gVideoWin, None);
+
+ XSelectInput(gDisplay, _window.clasped_window, VisibilityChangeMask | KeyPressMask | ButtonPressMask | SubstructureNotifyMask | StructureNotifyMask);
+ XMapRaised(lDisplay, _window.clasped_window);
+ XSync(lDisplay,0);
+ }
+
+ XSetStandardProperties(lDisplay, _window.clasped_window, _window.title, _window.title, None, NULL, 0, NULL);
+ XMoveResizeWindow(lDisplay, _window.clasped_window, (_mga_priv.bIsFullscreen) ? 0 : _mga_priv.image_xoff, (_mga_priv.bIsFullscreen) ? 0 : _mga_priv.image_yoff, (_mga_priv.bIsFullscreen) ? _display.width : _mga_priv.dest_width, (_mga_priv.bIsFullscreen) ? _display.height : _mga_priv.dest_height);
+ XMapRaised(lDisplay, _window.clasped_window);
+ XSync(lDisplay,0);
+}
+
+
+
+/* setup internal variables and (re-)init window if necessary */
+static int set_image_format_mga (uint32_t width, uint32_t height, uint32_t ratio, int format) {
+
+
+ double res_h, res_v, display_ratio, aspect_ratio;
+
+ if ( (_mga_priv.image_width == width)
+ && (_mga_priv.image_height == height)
+ && (_mga_priv.ratio == ratio)
+ && (_mga_priv.bFullscreen == _mga_priv.bIsFullscreen)
+ && (_mga_priv.fourcc_format == format)
+ && !_mga_priv.user_ratio_changed ) {
+
+
+ return 0;
+ }
+
+ _mga_priv.image_width = width;
+ _mga_priv.image_height = height;
+ _mga_priv.ratio = ratio;
+ _mga_priv.fourcc_format = format;
+ _mga_priv.user_ratio_changed = 0;
+
+
+ /*
+ * Mpeg-2:
+ */
+
+ res_h = 1; // _display.width;
+ res_v = 1; // _display.height;
+
+ display_ratio = res_h / res_v;
+
+ xprintf (VERBOSE | VIDEO, "display_ratio : %f\n",display_ratio);
+
+ if (_mga_priv.user_ratio == ASPECT_AUTO) {
+ switch (_mga_priv.ratio) {
+ case 0: /* forbidden */
+ fprintf (stderr, "invalid ratio\n");
+ exit (1);
+ break;
+ case 1: /* "square" => 4:3 */
+ case 2:
+ aspect_ratio = 4.0 / 3.0;
+ break;
+ case 3:
+ aspect_ratio = 16.0 / 9.0;
+ break;
+ case 42: /* some stupid stream => don't touch aspect ratio */
+ default:
+ xprintf (VIDEO, "unknown aspect ratio (%d) in stream. untouched.\n", _mga_priv.ratio);
+ aspect_ratio = (double)_mga_priv.image_width / (double)_mga_priv.image_height;
+ break;
+ }
+ } else if (_mga_priv.user_ratio == ASPECT_ANAMORPHIC) {
+ aspect_ratio = 16.0 / 9.0;
+ } else if (_mga_priv.user_ratio == ASPECT_DVB) {
+ aspect_ratio = 2.0 / 1.0;
+ } else {
+ aspect_ratio = 1.0;
+ }
+ aspect_ratio *= display_ratio;
+ if (_mga_priv.image_height * aspect_ratio >= _mga_priv.image_width) {
+ _mga_priv.orig_width = rint((double)((double)_mga_priv.image_height * aspect_ratio));
+ _mga_priv.orig_height = _mga_priv.image_height;
+ }
+ else {
+ _mga_priv.orig_width = _mga_priv.image_width;
+ _mga_priv.orig_height = rint((double)((double)_mga_priv.image_width / aspect_ratio));
+ }
+
+
+ xprintf (VERBOSE|VIDEO, "picture size : %d x %d (Ratio: %d)\n",
+ width, height, ratio);
+
+ setup_window_mga () ;
+
+ return 1;
+}
+
+static void dispose_image_buffer_mga (vo_image_buffer_t *image) {
+
+ free (image->mem[0]);
+ free (image);
+
+}
+
+static vo_image_buffer_t *alloc_image_buffer_mga () {
+
+ vo_image_buffer_t *image;
+
+ if (!(image = malloc (sizeof (vo_image_buffer_t))))
+ return NULL;
+
+ // we only know how to do 4:2:0 planar yuv right now.
+ // we prepare for YUY2 sizes
+ if (!(image->mem[0] = malloc (_mga_priv.image_width * _mga_priv.image_height * 2))) {
+ free(image);
+ return NULL;
+ }
+
+ image->mem[2] = image->mem[0] + _mga_priv.image_width * _mga_priv.image_height;
+ image->mem[1] = image->mem[0] + _mga_priv.image_width * _mga_priv.image_height * 5 / 4;
+
+ pthread_mutex_init (&image->mutex, NULL);
+
+ return image;
+}
+
+static void process_macroblock_mga (vo_image_buffer_t *img,
+ uint8_t *py, uint8_t *pu, uint8_t *pv,
+ int slice_offset,
+ int offset){
+}
+
+int is_fullscreen_mga () {
+ return _mga_priv.bFullscreen;
+}
+
+void set_fullscreen_mga (int bFullscreen) {
+ _mga_priv.bFullscreen = bFullscreen;
+
+
+ set_image_format_mga (_mga_priv.image_width, _mga_priv.image_height, _mga_priv.ratio,
+ _mga_priv.fourcc_format);
+
+}
+
+
+static void display_frame_mga(vo_image_buffer_t *vo_img) {
+
+ // only write frame if overlay is active (otherwise syncfb hangs)
+ if (_mga_priv.overlay_state == 1) {
+ ioctl(_mga_priv.fd,SYNCFB_REQUEST_BUFFER,&_mga_priv.bufinfo);
+ //printf("get buffer %d\n",_mga_priv.bufinfo.id);
+ if ( _mga_priv.bufinfo.id == -1 ) {
+ printf( "Got buffer #%d\n", _mga_priv.bufinfo.id );
+ return;
+ }
+
+ _mga_priv.vid_data = (uint_8 *)(_mga_priv.frame0 + _mga_priv.bufinfo.offset);
+
+ _mga_write_frame_g400(vo_img->mem);
+
+ ioctl(_mga_priv.fd,SYNCFB_COMMIT_BUFFER,&_mga_priv.bufinfo);
+ }
+ /* Image is copied so release buffer */
+ vo_image_drawn ( (vo_image_buffer_t *) vo_img);
+}
+
+#if 0
+void draw_logo_xv () {
+ XClearWindow (gDisplay, gXv.window);
+
+ XCopyArea (gDisplay, gXineLogo, gXv.window, gXv.gc, 0, 0,
+ gXineLogoWidth, gXineLogoHeight,
+ (gXv.dest_width - gXineLogoWidth)/2,
+ (gXv.dest_height - gXineLogoHeight)/2);
+
+ XFlush(gDisplay);
+}
+#endif
+
+void handle_event_mga (XEvent *event) {
+ switch (event->type) {
+ case VisibilityNotify:
+ if (event->xany.window == _window.clasped_window) {
+ if (event->xvisibility.state == VisibilityFullyObscured)
+ {
+ _window.visibility = 0;
+
+ if (_mga_priv.overlay_state == 1) {
+ if (ioctl(_mga_priv.fd,SYNCFB_OFF)) {
+ xprintf(VERBOSE|VIDEO,"Error in OFF ioctl\n");
+ }
+ else
+ _mga_priv.overlay_state = 0;
+ }
+ }
+ else
+ {
+ _window.visibility = 1;
+
+ if (_mga_priv.overlay_state == 0 && !_mga_priv.bLogoMode) {
+ if (ioctl(_mga_priv.fd,SYNCFB_GET_CONFIG,&_mga_priv.mga_vid_config))
+ printf("Error in get_config ioctl\n");
+ if (ioctl(_mga_priv.fd,SYNCFB_SET_CONFIG,&_mga_priv.mga_vid_config))
+ printf("Error in get_config ioctl\n");
+ if (ioctl(_mga_priv.fd,SYNCFB_ON)) {
+ xprintf(VERBOSE|VIDEO,"Error in ON ioctl\n");
+ }
+ else
+ _mga_priv.overlay_state = 1;
+ }
+ }
+ }
+ break;
+ }
+}
+
+void set_logo_mode_mga (int bLogoMode) {
+ if (_mga_priv.bLogoMode == bLogoMode)
+ return;
+
+ _mga_priv.bLogoMode = bLogoMode;
+
+ if (bLogoMode) {
+ if (ioctl(_mga_priv.fd,SYNCFB_OFF)) {
+ xprintf(VERBOSE|VIDEO,"Error in OFF ioctl\n");
+ }
+ else
+ _mga_priv.overlay_state = 0;
+ }
+ else {
+ if (_window.visibility == 1) {
+ if (ioctl(_mga_priv.fd,SYNCFB_GET_CONFIG,&_mga_priv.mga_vid_config))
+ printf("Error in get_config ioctl\n");
+ if (ioctl(_mga_priv.fd,SYNCFB_SET_CONFIG,&_mga_priv.mga_vid_config))
+ printf("Error in get_config ioctl\n");
+ if (ioctl(_mga_priv.fd,SYNCFB_ON)) {
+ xprintf(VERBOSE|VIDEO,"Error in ON ioctl\n");
+ }
+ else {
+ _mga_priv.overlay_state = 1;
+ }
+ }
+ }
+
+#if 0
+ XLOCK
+ if (bLogoMode)
+ draw_logo_xv ();
+ else { /* FIXME : Bad hack to reinstall Xv overlay */
+ XUnmapWindow(gDisplay, gXv.window);
+ XMapRaised(gDisplay, gXv.window);
+
+ /* Spark
+ * move the window back to 0,0 in case the window manager moved it
+ * do this only is the window is fullscreen or
+ * we lose the top and left windowborders
+ */
+ if (gXv.bIsFullscreen) {
+ XMoveWindow(gDisplay, gXv.window, 0, 0);
+ }
+
+ }
+ XUNLOCK
+#endif
+}
+
+void reset_mga () {
+}
+
+void display_cursor_mga () {
+}
+
+void set_aspect_mga (int ratio) {
+
+ ratio %= 4;
+
+ if (ratio != _mga_priv.user_ratio) {
+ _mga_priv.user_ratio = ratio;
+ _mga_priv.user_ratio_changed = 1;
+
+ set_image_format_mga (_mga_priv.image_width, _mga_priv.image_height, _mga_priv.ratio, _mga_priv.fourcc_format);
+ }
+}
+
+int get_aspect_mga () {
+ return _mga_priv.user_ratio;
+}
+
+void exit_mga () {
+printf("exit mga\n");
+ if (ioctl(_mga_priv.fd,SYNCFB_ON)) {
+ xprintf(VERBOSE|VIDEO,"Error in ON ioctl\n");
+ }
+ if (ioctl(_mga_priv.fd,SYNCFB_OFF)) {
+ xprintf(VERBOSE|VIDEO,"Error in OFF ioctl\n");
+ }
+ close(_mga_priv.fd);
+ _mga_priv.fd = -1;
+}
+
+static int get_noop(void) {
+ return 0;
+}
+
+static int set_noop(int v) {
+ return v;
+}
+
+/*
+ * Contrast settings
+ */
+static int get_contrast_min(void) {
+ return _mga_priv.cont_min;
+}
+static int get_current_contrast(void) {
+ return _mga_priv.cont_current;
+}
+static int set_contrast(int value) {
+
+ _mga_priv.param.contrast = value;
+ _mga_priv.param.brightness = _mga_priv.bright_current;
+
+ if (ioctl(_mga_priv.fd,SYNCFB_SET_PARAMS,&_mga_priv.param) == 0) {
+ _mga_priv.cont_current = _mga_priv.param.contrast;
+ return _mga_priv.cont_current;
+ }
+ return value;
+}
+
+static int get_contrast_max(void) {
+ return _mga_priv.cont_max;
+}
+
+/*
+ * Brightness settings
+ */
+static int get_brightness_min(void) {
+ return _mga_priv.bright_min;
+}
+static int get_current_brightness(void) {
+ return _mga_priv.bright_current;
+}
+static int set_brightness(int value) {
+
+ _mga_priv.param.brightness = value;
+ _mga_priv.param.contrast = _mga_priv.cont_current;
+
+ if (ioctl(_mga_priv.fd,SYNCFB_SET_PARAMS,&_mga_priv.param) == 0) {
+ _mga_priv.bright_current = _mga_priv.param.brightness;
+ return _mga_priv.bright_current;
+ }
+ return value;
+}
+
+static int get_brightness_max(void) {
+ return _mga_priv.bright_max;
+}
+
+static void reset_settings(void) {
+ set_contrast(config_file_lookup_int ("contrast", _mga_priv.cont_current));
+ set_brightness(config_file_lookup_int ("brightness", _mga_priv.bright_current));
+}
+
+static void save_settings(void) {
+ config_file_set_int ("brightness", _mga_priv.bright_current);
+ config_file_set_int ("contrast", _mga_priv.cont_current);
+}
+
+
+static vo_driver_t vo_mga = {
+ get_capabilities_mga,
+ set_image_format_mga,
+ alloc_image_buffer_mga,
+ dispose_image_buffer_mga,
+ process_macroblock_mga,
+ display_frame_mga,
+ set_fullscreen_mga,
+ is_fullscreen_mga,
+ handle_event_mga,
+ set_logo_mode_mga,
+ reset_mga,
+ display_cursor_mga,
+ set_aspect_mga,
+ get_aspect_mga,
+ exit_mga,
+ /* HUE min, current, set , max */
+ get_noop,
+ get_noop,
+ set_noop,
+ get_noop,
+
+ /* SATURATION min, current, set , max */
+ get_noop,
+ get_noop,
+ set_noop,
+ get_noop,
+
+ /* Brightness min, current, set , max */
+ get_brightness_min,
+ get_current_brightness,
+ set_brightness,
+ get_brightness_max,
+
+ /* Contrast min, current, set , max */
+ get_contrast_min,
+ get_current_contrast,
+ set_contrast,
+ get_contrast_max,
+
+ /* Colorkey min , current set */
+ get_noop,
+ get_noop,
+ set_noop,
+ reset_settings,
+ save_settings
+};
+
+
+/*
+ * connect to server, create and map window,
+ * allocate colors and (shared) memory
+ */
+
+vo_driver_t *init_video_out_mga () {
+
+ char name[]= "/dev/syncfb";
+
+ _mga_priv.image_width=720;
+ _mga_priv.image_height=576;
+
+
+ if ((_mga_priv.fd = open ((char *) name, O_RDWR)) < 0) {
+ xprintf(VERBOSE|VIDEO, "Can't open %s\n", (char *) name);
+ return 0;
+ }
+
+ if (ioctl(_mga_priv.fd,SYNCFB_GET_CAPS,&_mga_priv.caps)) {
+ xprintf(VERBOSE|VIDEO,"Error in config ioctl");
+ close(_mga_priv.fd);
+ return 0;
+ }
+
+ _mga_priv.vid_data = (char*)mmap(0,_mga_priv.caps.memory_size,PROT_WRITE,MAP_SHARED,_mga_priv.fd,0);
+
+ //clear the buffer
+// memset(_mga_priv.vid_data,0,1024*768*2);
+
+
+ _mga_priv.frame0 = _mga_priv.vid_data;
+
+
+
+ /*
+ * init global variables
+ */
+
+ strcpy(_window.title, "Xine syncfb overlay\0");
+ _window.visibility = 1;
+
+ lDisplay = XOpenDisplay(":0.0"); /* Xine may run on another Display but syncfb always goes to :0.0 */
+// lDisplay = gDisplay;
+ _mga_priv.bFullscreen = 0;
+ _mga_priv.bIsFullscreen = 0;
+ _mga_priv.image_width = 0;
+ _mga_priv.image_height = 0;
+ _mga_priv.ratio = 0;
+ _mga_priv.bLogoMode = 0;
+// _mga_priv.cur_image = NULL;
+ _mga_priv.user_ratio = ASPECT_AUTO;
+ _mga_priv.user_ratio_changed = 0 ;
+ _mga_priv.fourcc_format = 0;
+
+ _window.clasped_window = 0;
+ _display.default_screen = DefaultScreen(lDisplay);
+ _mga_priv.cont_min = 0;
+ _mga_priv.cont_max = 255;
+ _mga_priv.bright_max = 127;
+ _mga_priv.bright_min = -128;
+
+ _mga_priv.overlay_state = 0; // 0 = off, 1 = on
+
+ if (ioctl(_mga_priv.fd,SYNCFB_GET_PARAMS,&_mga_priv.param) == 0) {
+ _mga_priv.cont_current = _mga_priv.param.contrast;
+ _mga_priv.bright_current = _mga_priv.param.brightness;
+ }
+ else {
+ _mga_priv.cont_current = 0x80;
+ _mga_priv.bright_current = 0;
+ xprintf(VERBOSE|VIDEO,"syncfb:Brightness and Contrast control not available, please update your syncfb module");
+ printf("syncfb:Brightness and Contrast control not available, please update your syncfb module\n");
+
+ }
+
+ set_logo_mode_mga(1);
+
+ return &vo_mga;
+}
+
+/* #else *//* no MGA */
+
+/* vo_functions_t *init_video_out_xv () { */
+/* fprintf (stderr, "Xvideo support not compiled in\n"); */
+/* return NULL; */
+/* } */
+
+/* #endif */ /* HAVE_XV */
diff --git a/src/video_out/video_out_syncfb.h b/src/video_out/video_out_syncfb.h
new file mode 100644
index 000000000..96503ca89
--- /dev/null
+++ b/src/video_out/video_out_syncfb.h
@@ -0,0 +1,240 @@
+#ifndef __LINUX_SYNCFB_H
+#define __LINUX_SYNCFB_H
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/videodev.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#define TRUE 1
+#define FALSE 0
+
+#define SFB_STATUS_FREE 0
+#define SFB_STATUS_OFFS 1
+#define SFB_STATUS_WAIT 2
+#define SFB_STATUS_LIVE 3
+
+#endif /* KERNEL */
+
+
+#ifndef AARONS_TYPES
+typedef unsigned long uint_32;
+typedef unsigned char uint_8;
+#endif
+
+#define SYNCFB_MAJOR 178
+
+#define SYNCFB_ERROR_NO_ERROR 0;
+#define SYNCFB_ERROR_NO_BUFFER_AVAILABLE 1;
+#define SYNCFB_ERROR_PALETTE_NOT_SUPPORTED 2;
+#define SYNCFB_ERROR_NOT_ENOUGH_MEMORY 3;
+
+
+
+#ifndef __LINUX_VIDEODEV_H
+#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */
+#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */
+#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */
+#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */
+#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */
+#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */
+#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */
+#define VIDEO_PALETTE_YUYV 8
+#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */
+#define VIDEO_PALETTE_YUV420 10
+#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */
+#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */
+#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */
+#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */
+#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */
+#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */
+#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */
+#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */
+#endif
+
+
+#define VIDEO_PALETTE_YUV422P3 13 /* YUV 4:2:2 Planar (3 Plane, same as YUV422P) */
+#define VIDEO_PALETTE_YUV422P2 17 /* YUV 4:2:2 Planar (2 Plane) */
+
+#define VIDEO_PALETTE_YUV411P3 14 /* YUV 4:1:1 Planar (3 Plane, same as YUV411P) */
+#define VIDEO_PALETTE_YUV411P2 18 /* YUV 4:1:1 Planar (2 Plane) */
+
+#define VIDEO_PALETTE_YUV420P3 15 /* YUV 4:2:0 Planar (3 Plane, same as YUV420P) */
+#define VIDEO_PALETTE_YUV420P2 19 /* YUV 4:2:0 Planar (2 Plane) */
+
+#define VIDEO_PALETTE_YUV410P3 16 /* YUV 4:1:0 Planar (3 Plane, same as YUV410P) */
+#define VIDEO_PALETTE_YUV410P2 20 /* YUV 4:1:0 Planar (2 Plane) */
+
+
+
+#define SYNCFB_FEATURE_SCALE_H 1
+#define SYNCFB_FEATURE_SCALE_V 2
+#define SYNCFB_FEATURE_SCALE 3
+#define SYNCFB_FEATURE_CROP 4
+#define SYNCFB_FEATURE_OFFSET 8
+#define SYNCFB_FEATURE_DEINTERLACE 16
+#define SYNCFB_FEATURE_PROCAMP 32
+#define SYNCFB_FEATURE_TRANSITIONS 64
+#define SYNCFB_FEATURE_COLKEY 128
+#define SYNCFB_FEATURE_MIRROR_H 256
+#define SYNCFB_FEATURE_MIRROR_V 512
+#define SYNCFB_FEATURE_BLOCK_REQUEST 1024
+#define SYNCFB_FEATURE_FREQDIV2 2048
+
+
+typedef struct syncfb_config_s
+{
+ uint_32 syncfb_mode; /* bitfield: turn on/off the available features */
+ uint_32 error_code; /* RO: returns 0 on successful config calls, error code otherwise */
+
+ uint_32 fb_screen_size; /* WO, size in bytes of video memory reserved for fbdev */
+ uint_32 fb_screen_width; /* WO, visible screen width in pixel */
+ uint_32 fb_screen_height; /* WO, visible screen height in pixel */
+
+ uint_32 buffers; /* RO, number of available buffers */
+ uint_32 buffer_size; /* RO, filled in by syncfb */
+
+ uint_32 default_repeat; /* default repeat time for a single frame, can be overridden in syncfb_buffer_info_t */
+
+ uint_32 src_width; /* source image width in pixel */
+ uint_32 src_height; /* source image height in pixel */
+ uint_32 src_palette; /* set palette mode, see videodev.h for palettes */
+ uint_32 src_pitch; /* RO: filled in by ioctl: actual line length in pixel */
+
+ uint_32 image_xorg; /* x position of the image on the screen */
+ uint_32 image_yorg; /* y position of the image on the screen */
+
+ /* if syncfb has FEATURE_SCALE */
+ uint_32 scale_filters; /* 0: no filtering, 255: all filters on */
+ uint_32 image_width; /* onscreen image width */
+ uint_32 image_height; /* onscreen image height */
+
+ /* if syncfb has FEATURE_CROP */
+ uint_32 src_crop_left; /* */
+ uint_32 src_crop_right; /* */
+ uint_32 src_crop_top; /* */
+ uint_32 src_crop_bot; /* */
+
+ /* if syncfb has FEATURE_OFFSET */
+ uint_32 image_offset_left; /* */
+ uint_32 image_offset_right; /* */
+ uint_32 image_offset_top; /* */
+ uint_32 image_offset_bot; /* */
+
+ /* if syncfb has FEATURE_COLKEY */
+ uint_8 colkey_red;
+ uint_8 colkey_green;
+ uint_8 colkey_blue;
+
+} syncfb_config_t;
+
+
+/*
+ picture parameters,
+*/
+typedef struct syncfb_param_s
+{
+ /* the idea is to enable smooth transitions between eg. image sizes (not yet implemented) */
+ /* if syncfb has FEATURE_TRANSITIONS */
+ uint_32 transition_time;
+
+ /* if syncfb has FEATURE_PROCAMP */
+ uint_32 contrast; /* 0: least contrast, 1000: normal contrast, */
+ uint_32 brightness;
+ uint_32 color; /* for syncfb_matrox: color=0: b/w else: full color */
+
+ /* if syncfb has FEATURE_SCALE , currently only supported in CONFIG call */
+ uint_8 scale_filters; /* 0: no filtering, 255: all filters on */
+ uint_32 image_xorg; /* x position of the image on the screen */
+ uint_32 image_yorg; /* y position of the image on the screen */
+ uint_32 image_width; /* onscreen image width */
+ uint_32 image_height; /* onscreen image height */
+
+} syncfb_param_t;
+
+
+
+typedef struct syncfb_status_info_s
+{
+ uint_32 field_cnt; /* basically all vbi's since the start of syncfb */
+ uint_32 frame_cnt; /* number of frames comitted & output */
+
+ uint_32 hold_field_cnt; /* number of repeated fields becaus no new data was available */
+ uint_32 skip_field_cnt; /* skipped fields when fifo was about to fill up */
+
+ uint_32 request_frames; /* number of request_buffer calls */
+ uint_32 commit_frames; /* number of commit_buffer calls */
+
+ uint_32 failed_requests; /* number of calls to request_buffer that failed */
+
+ uint_32 buffers_waiting;
+ uint_32 buffers_free;
+
+} syncfb_status_info_t;
+
+
+
+
+typedef struct syncfb_capability_s
+{
+ char name[64]; /* A name for the syncfb ... */
+ uint_32 palettes; /* supported palettes - see videodev.h for palettes, test the corresponding bit here */
+ uint_32 features; /* supported features - see SYNCFB_FEATURE_* */
+ uint_32 memory_size; /* total size of mappable video memory */
+
+} syncfb_capability_t;
+
+
+
+typedef struct syncfb_buffer_info_s
+{
+ int id; /* buffer id: a return value of -1 means no buffer available */
+ uint_32 repeat; /* the buffer will be shown <repeat> times */
+ uint_32 offset; /* buffer offset from start of video memory */
+ uint_32 offset_p2; /* yuv plane 2 buffer offset from start of video memory */
+ uint_32 offset_p3; /* yuv plane 3 buffer offset from start of video memory */
+
+} syncfb_buffer_info_t;
+
+
+
+
+
+
+
+/* get syncfb capabilities */
+#define SYNCFB_GET_CAPS _IOR('J', 1, syncfb_config_t)
+
+#define SYNCFB_GET_CONFIG _IOR('J', 2, syncfb_config_t)
+#define SYNCFB_SET_CONFIG _IOR('J', 3, syncfb_config_t)
+#define SYNCFB_ON _IO ('J', 4)
+#define SYNCFB_OFF _IO ('J', 5)
+#define SYNCFB_REQUEST_BUFFER _IOR ('J', 6, syncfb_buffer_info_t)
+#define SYNCFB_COMMIT_BUFFER _IOR ('J', 7, syncfb_buffer_info_t)
+#define SYNCFB_STATUS _IOR ('J', 8, syncfb_status_info_t)
+#define SYNCFB_VBI _IO ('J', 9) /* simulate interrupt - debugging only */
+#define SYNCFB_SET_PARAMS _IOR('J', 10, syncfb_param_t)
+#define SYNCFB_GET_PARAMS _IOR('J', 11, syncfb_param_t)
+
+
+
+
+#endif /* __LINUX_SYNCFB_H */
+
diff --git a/src/video_out/video_out_xshm.c b/src/video_out/video_out_xshm.c
new file mode 100644
index 000000000..61531225f
--- /dev/null
+++ b/src/video_out/video_out_xshm.c
@@ -0,0 +1,968 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: video_out_xshm.c,v 1.1 2001/04/24 20:53:00 f1rmb Exp $
+ *
+ * video_out_xshm.c, X11 shared memory extension interface for xine
+ *
+ * based on mpeg2dec code from
+ * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * xine-specific code by Guenter Bartsch <bartscgr@studbox.uni-stuttgart.de>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "video_out.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <errno.h>
+
+#include <X11/extensions/XShm.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+
+#include <Imlib.h>
+#include <pthread.h>
+
+#include "xine_internal.h"
+#include "monitor.h"
+#include "libmpeg2/mpeg2.h"
+#include "yuv2rgb.h"
+#warning "FIXME"
+#include "../gui/gui_dnd.h"
+#include "../gui/gui_main.h"
+
+extern uint32_t xine_debug;
+
+extern int XShmGetEventBase(Display *);
+
+extern Display *gDisplay;
+extern pthread_mutex_t gXLock;
+extern Window gVideoWin;
+extern ImlibImage *gXineLogoImg;
+extern ImlibData *gImlib_data;
+extern Pixmap gXineLogo;
+extern int gXineLogoWidth, gXineLogoHeight;
+
+typedef struct xshm_image_info_s {
+ vo_image_buffer_t mImageBuffer;
+ XImage *mImage;
+ XShmSegmentInfo mShminfo;
+} xshm_image_buffer_t;
+
+typedef struct _xshm_globals {
+ int screen;
+ Window window;
+ XVisualInfo vinfo;
+ int depth,bpp;
+ int bFullscreen;
+ int bIsFullscreen;
+ GC gc;
+ uint32_t image_width;
+ uint32_t image_height;
+ uint32_t image_xoff;
+ uint32_t image_yoff;
+ uint32_t dest_width;
+ uint32_t dest_height;
+ uint32_t ratio;
+ int user_ratio, user_ratio_changed;
+ int bYuvInitialized;
+ int bytes_per_pixel;
+ int hstride_rgb, hstride_y, hstride_uv;
+ int anamorphic;
+
+
+ xshm_image_buffer_t *cur_image;
+
+ /*
+ * misc (read: fun ;))
+ */
+ int bLogoMode;
+
+#define HIDE_CURSOR 0
+#define SHOW_CURSOR 1
+ Cursor mcursor[2];
+ int current_cursor;
+
+ int bFail;
+ int bUseShm;
+ DND_struct_t *xdnd;
+} xshm_globals;
+
+
+xshm_globals gXshm ;
+
+int HandleXError (Display *gDisplay, XErrorEvent *xevent) {
+
+ xprintf (VERBOSE|VIDEO, "\n\n*** X ERROR *** \n\n\n");
+
+ gXshm.bFail = 1;
+ return 0;
+
+}
+
+static void x11_InstallXErrorHandler ()
+{
+ XSetErrorHandler (HandleXError);
+ XFlush (gDisplay);
+}
+
+static void x11_DeInstallXErrorHandler ()
+{
+ XSetErrorHandler (NULL);
+ XFlush (gDisplay);
+}
+
+static int get_capabilities_xshm () {
+ return VO_CAP_COPIES_IMAGE | VO_CAP_YV12;
+}
+
+static unsigned char bm_no_data[] = { 0,0,0,0, 0,0,0,0 };
+
+static void create_cursor_xshm (Colormap colormap) {
+ Pixmap bm_no;
+ XColor black, dummy;
+
+ /*
+ * create empty cursor
+ */
+
+ bm_no = XCreateBitmapFromData(gDisplay, gXshm.window,
+ bm_no_data, 8, 8);
+
+ XAllocNamedColor(gDisplay,colormap,"black",&black,&dummy);
+ gXshm.mcursor[0] = XCreatePixmapCursor(gDisplay, bm_no, bm_no,
+ &black, &black,
+ 0, 0);
+ gXshm.mcursor[1]= XCreateFontCursor(gDisplay, XC_left_ptr);
+
+}
+
+static void display_cursor_xshm(int state) {
+
+ XDefineCursor(gDisplay, gXshm.window, gXshm.mcursor[state]);
+ gXshm.current_cursor = state;
+}
+
+static void setup_window_xshm () {
+ char *hello = "xine video output";
+ Colormap theCmap = 0;
+ XSizeHints hint;
+ XWMHints *wm_hint;
+ XEvent xev;
+ XGCValues xgcv;
+ XColor background, ignored;
+ XSetWindowAttributes attr;
+ int ww, wh;
+ float aspect;
+ Atom WM_DELETE_WINDOW;
+ XClassHint *xshm_xclasshint;
+
+ XLOCK ();
+
+
+ if((xshm_xclasshint = XAllocClassHint()) != NULL) {
+ xshm_xclasshint->res_name = "Xine Xshm Video";
+ xshm_xclasshint->res_class = "Xine";
+ }
+
+ if (gXshm.bFullscreen) {
+
+ ww = DisplayWidth (gDisplay, gXshm.screen);
+ wh = DisplayHeight (gDisplay, gXshm.screen);
+
+ /*
+ * zoom to fullscreen
+ */
+
+ if (gXshm.dest_width < ww) {
+ aspect = (float) gXshm.dest_width / (float) gXshm.dest_height ;
+
+ gXshm.dest_width = ww;
+ gXshm.dest_height = ww / aspect;
+ }
+
+ gXshm.image_xoff = ( ww - gXshm.dest_width) / 2;
+ gXshm.image_yoff = ( wh - gXshm.dest_height) / 2;
+
+
+ if (gXshm.window) {
+
+ if (gXshm.bIsFullscreen) {
+ XUNLOCK ();
+ return;
+ }
+
+ XDestroyWindow(gDisplay, gXshm.window);
+ gXshm.window = 0;
+
+ }
+
+ gXshm.bIsFullscreen = 1;
+
+ /*
+ * open fullscreen window
+ */
+
+ if (XAllocNamedColor (gDisplay, DefaultColormap (gDisplay, gXshm.screen),
+ "black",
+ &background, &ignored) == 0) {
+ fprintf (stderr, "Cannot allocate color black\n");
+ exit(1);
+ }
+
+ attr.background_pixel = background.pixel;
+ attr.override_redirect = True;
+
+ gXshm.window =
+ XCreateWindow (gDisplay, RootWindow (gDisplay, gXshm.screen), 0, 0,
+ ww, wh, 0, gXshm.depth,
+ CopyFromParent, DefaultVisual (gDisplay, gXshm.screen),
+ CWBackPixel|CWOverrideRedirect, &attr);
+
+ if(xshm_xclasshint != NULL)
+ XSetClassHint(gDisplay, gXshm.window, xshm_xclasshint);
+
+ gVideoWin = gXshm.window;
+
+ } else {
+
+ if (gXshm.window) {
+
+ if (gXshm.bIsFullscreen) {
+ XDestroyWindow(gDisplay, gXshm.window);
+ gXshm.window = 0;
+ } else {
+
+ XResizeWindow (gDisplay, gXshm.window, gXshm.dest_width,
+ gXshm.dest_height);
+
+ XFlush(gDisplay);
+ XSync(gDisplay, False);
+ XUNLOCK ();
+ return;
+
+ }
+ }
+
+ gXshm.bIsFullscreen = 0;
+
+
+ hint.x = 0;
+ hint.y = 0;
+ hint.width = gXshm.dest_width;
+ hint.height = gXshm.dest_height;
+ hint.flags = PPosition | PSize;
+
+ theCmap = XCreateColormap(gDisplay, RootWindow(gDisplay,gXshm.screen),
+ gXshm.vinfo.visual, AllocNone);
+
+ attr.background_pixel = 0;
+ attr.border_pixel = 1;
+ attr.colormap = theCmap;
+
+ gXshm.window = XCreateWindow(gDisplay, RootWindow(gDisplay, gXshm.screen),
+ hint.x, hint.y, hint.width, hint.height, 4,
+ gXshm.depth,CopyFromParent,gXshm.vinfo.visual,
+ CWBackPixel | CWBorderPixel |CWColormap,&attr);
+
+ if(xshm_xclasshint != NULL)
+ XSetClassHint(gDisplay, gXshm.window, xshm_xclasshint);
+
+ gVideoWin = gXshm.window;
+
+ /* Tell other applications about this window */
+
+ XSetStandardProperties(gDisplay, gXshm.window, hello, hello,
+ None, NULL, 0, &hint);
+
+ gXshm.image_xoff = 0;
+ gXshm.image_yoff = 0;
+ }
+
+ XSelectInput(gDisplay, gXshm.window, StructureNotifyMask | ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask);
+
+ wm_hint = XAllocWMHints();
+ if (wm_hint != NULL) {
+ wm_hint->input = True;
+ wm_hint->initial_state = NormalState;
+ wm_hint->flags = InputHint | StateHint;
+ XSetWMHints(gDisplay, gXshm.window, wm_hint);
+ XFree(wm_hint);
+ }
+
+ WM_DELETE_WINDOW = XInternAtom(gDisplay, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(gDisplay, gXshm.window, &WM_DELETE_WINDOW, 1);
+
+ /* Map window. */
+
+ XMapWindow(gDisplay, gXshm.window);
+
+ /* Wait for map. */
+ do {
+ XMaskEvent(gDisplay,
+ StructureNotifyMask,
+ &xev) ;
+ } while (xev.type != MapNotify || xev.xmap.event != gXshm.window);
+
+ XFlush(gDisplay);
+ XSync(gDisplay, False);
+
+ gXshm.gc = XCreateGC(gDisplay, gXshm.window, 0L, &xgcv);
+
+ if (gXshm.bFullscreen)
+ XSetInputFocus (gDisplay, gXshm.window, RevertToNone, CurrentTime);
+
+ if (gXshm.bFullscreen) {
+ if (!gXshm.mcursor[0]) {
+ create_cursor_xshm (theCmap);
+ }
+
+ //display_cursor_xshm(HIDE_CURSOR);
+ }
+ /* drag and drop */
+
+ XUNLOCK ();
+
+ if(!gXshm.xdnd)
+ gXshm.xdnd = (DND_struct_t *) malloc(sizeof(DND_struct_t));
+
+ gui_init_dnd(gXshm.xdnd);
+ gui_dnd_set_callback (gXshm.xdnd, gui_dndcallback);
+ gui_make_window_dnd_aware (gXshm.xdnd, gXshm.window);
+
+}
+
+/* allocates ximages if necessary */
+static int set_image_format_xshm (uint32_t width, uint32_t height, uint32_t ratio, int format) {
+
+ /* FIXME: handle format argument */
+
+ if ( (gXshm.image_width == width)
+ && (gXshm.image_height == height)
+ && (gXshm.ratio == ratio)
+ && (gXshm.bFullscreen == gXshm.bIsFullscreen)
+ && !gXshm.user_ratio_changed )
+ return 0;
+
+ gXshm.image_width = width;
+ gXshm.image_height = height;
+ gXshm.hstride_rgb = gXshm.dest_width * gXshm.bytes_per_pixel;
+ gXshm.hstride_y = gXshm.image_width;
+ gXshm.hstride_uv = gXshm.image_width / 2;
+ gXshm.ratio = ratio;
+ gXshm.user_ratio_changed = 0;
+
+ /*
+ * calculate dest size from ratio
+ */
+
+ /*
+ * Mpeg-2:
+ */
+
+ if (gXshm.user_ratio == ASPECT_AUTO) {
+ switch (gXshm.ratio) {
+ case 0: /* forbidden */
+ fprintf (stderr, "invalid ratio\n");
+ exit (1);
+ break;
+ case 1: /* square */
+ gXshm.dest_width = width;
+ gXshm.dest_height = height;
+ gXshm.anamorphic = 0;
+ break;
+ case 2: /* 4:3 */
+ gXshm.dest_width = width ;
+ gXshm.dest_height = height;
+ gXshm.anamorphic = 0;
+ break;
+ case 3: /* 16:9 */
+ gXshm.dest_width = width * 5/4;
+ gXshm.dest_height = height;
+ gXshm.anamorphic = 1;
+ break;
+ default:
+ gXshm.dest_width = width;
+ gXshm.dest_height = height;
+ xprintf (VERBOSE|VIDEO, "invalid ratio\n");
+ /*exit (1); */
+ break;
+ }
+ } else if (gXshm.user_ratio == ASPECT_ANAMORPHIC) {
+ gXshm.dest_width = width *5/4 ;
+ gXshm.dest_height = height;
+ gXshm.anamorphic = 1;
+ } else {
+ gXshm.dest_width = width;
+ gXshm.dest_height = height;
+ gXshm.anamorphic = 0;
+ }
+
+
+ xprintf (VERBOSE|VIDEO, "picture size : %d x %d (Ratio: %d)\n",
+ width, height, ratio);
+
+ setup_window_xshm () ;
+
+ return 1;
+}
+
+static void dispose_image_buffer_xshm (vo_image_buffer_t *vo_img) {
+
+ xshm_image_buffer_t *img = (xshm_image_buffer_t *) vo_img;
+
+ XLOCK ();
+
+ if (gXshm.bUseShm) {
+
+ XShmDetach(gDisplay, &img->mShminfo);
+ XDestroyImage(img->mImage);
+ shmdt(img->mShminfo.shmaddr);
+ shmctl (img->mShminfo.shmid, IPC_RMID,NULL);
+
+ } else {
+
+ XDestroyImage(img->mImage);
+
+ }
+
+ free (img);
+
+ XUNLOCK ();
+}
+
+
+static vo_image_buffer_t *alloc_image_buffer_xshm () {
+
+ uint32_t image_size;
+ xshm_image_buffer_t *img ;
+
+ XLOCK ();
+
+ img = (xshm_image_buffer_t *) malloc (sizeof (xshm_image_buffer_t));
+
+ if (img==NULL) {
+ printf ("out of memory while allocating image buffer\n");
+ exit (1);
+ }
+
+ if (gXshm.bUseShm) {
+ img->mImage = XShmCreateImage(gDisplay,
+ gXshm.vinfo.visual,
+ gXshm.vinfo.depth,
+ ZPixmap, NULL,
+ &img->mShminfo,
+ gXshm.dest_width,
+ gXshm.dest_height);
+
+ if (img->mImage == NULL ) {
+ fprintf(stderr, "Shared memory error when allocating image => exit (Ximage error)\n");
+ exit (1);
+ }
+
+ gXshm.bpp = img->mImage->bits_per_pixel;
+ gXshm.bytes_per_pixel = gXshm.bpp / 8;
+ gXshm.hstride_rgb = gXshm.dest_width * gXshm.bytes_per_pixel;
+ img->mShminfo.shmid=shmget(IPC_PRIVATE,
+ img->mImage->bytes_per_line * img->mImage->height,
+ IPC_CREAT | 0777);
+
+ if (img->mShminfo.shmid < 0 ) {
+ printf("%s: allocating image \n",strerror(errno));
+ exit (1);
+ }
+
+ img->mShminfo.shmaddr = (char *) shmat(img->mShminfo.shmid, 0, 0);
+
+ if (img->mShminfo.shmaddr == ((char *) -1)) {
+ fprintf(stderr, "Shared memory error (address error) when allocating image \n");
+ exit (1);
+ }
+
+ img->mShminfo.readOnly = False;
+ img->mImage->data = img->mShminfo.shmaddr;
+
+ XShmAttach(gDisplay, &img->mShminfo);
+
+ XSync(gDisplay, False);
+ /* shmctl(img->mShminfo.shmid, IPC_RMID, 0);*/
+ } else { /* no shm */
+
+ /*
+ XResizeWindow (gDisplay, gXshm.window, gXshm.dest_width,
+ gXshm.dest_height);
+
+ XSync(gDisplay, False);
+ */
+ img->mImage = XGetImage (gDisplay, gXshm.window, 0, 0,
+ gXshm.dest_width, gXshm.dest_height,
+ AllPlanes, ZPixmap);
+ XSync(gDisplay, False);
+ }
+
+
+ image_size = gXshm.image_width * gXshm.image_height;
+ img->mImageBuffer.mem[0] = malloc(image_size);
+ img->mImageBuffer.mem[1] = malloc(image_size/4);
+ img->mImageBuffer.mem[2] = malloc(image_size/4);
+
+ if (!gXshm.bYuvInitialized) {
+ int mode = ((img->mImage->blue_mask & 0x01)) ? MODE_RGB : MODE_BGR;
+ yuv2rgb_init((gXshm.depth == 24) ? gXshm.bpp : gXshm.depth, mode);
+ gXshm.bYuvInitialized = 1;
+ }
+
+ XUNLOCK ();
+
+ pthread_mutex_init (&img->mImageBuffer.mutex, NULL);
+
+ return (vo_image_buffer_t *) img;
+}
+
+static void process_macroblock_xshm (vo_image_buffer_t *img,
+ uint8_t *py, uint8_t *pu, uint8_t *pv,
+ int slice_num,
+ int subslice_num) {
+
+ uint8_t *dst;
+ int subslice_offset;
+ xshm_image_buffer_t *xshm_img = (xshm_image_buffer_t *) img;
+ int slice_offset;
+
+ slice_offset = slice_num * 16 * gXshm.dest_width ;
+ if (gXshm.anamorphic)
+ subslice_offset = subslice_num *20 ;
+ else
+ subslice_offset = subslice_num *16 ;
+
+ dst = xshm_img->mImage->data + (slice_offset + subslice_offset) * gXshm.bytes_per_pixel ;
+
+ if (gXshm.anamorphic)
+ yuv2rgb_anamorphic(dst,
+ py, pu, pv,
+ gXshm.hstride_rgb,
+ gXshm.hstride_y,
+ gXshm.hstride_uv);
+ else
+ yuv2rgb(dst,
+ py, pu, pv,
+ gXshm.hstride_rgb,
+ gXshm.hstride_y,
+ gXshm.hstride_uv);
+}
+
+static int is_fullscreen_xshm () {
+ return gXshm.bFullscreen;
+}
+
+static void set_fullscreen_xshm (int bFullscreen) {
+
+ xprintf(VERBOSE|VIDEO, "(!)Fullscreen not implemented for xshm.\n");
+
+ return ; /* FIXME - not implemented for xshm */
+
+ gXshm.bFullscreen = bFullscreen;
+
+ set_image_format_xshm (gXshm.image_width, gXshm.image_height, gXshm.ratio, IMGFMT_YV12);
+}
+
+static void display_frame_xshm (vo_image_buffer_t *vo_img) {
+
+ xshm_image_buffer_t *img = (xshm_image_buffer_t *) vo_img;
+
+ XLOCK ();
+
+ if (gXshm.bUseShm) {
+
+ XShmPutImage(gDisplay, gXshm.window, gXshm.gc, img->mImage,
+ 0, 0, 0, 0,
+ img->mImage->width, img->mImage->height, True);
+ } else {
+
+ xprintf (VERBOSE|VIDEO, "display frame\n");
+
+ XPutImage(gDisplay, gXshm.window, gXshm.gc, img->mImage,
+ 0, 0, 0, 0,
+ img->mImage->width, img->mImage->height);
+ }
+
+ XFlush(gDisplay);
+
+ if (gXshm.cur_image) {
+ vo_image_drawn ( (vo_image_buffer_t *) gXshm.cur_image);
+ }
+
+ gXshm.cur_image = img;
+
+ XUNLOCK ();
+}
+
+static void draw_logo_xshm () {
+ ImlibImage *resized_image;
+ int xwin, ywin, tmp;
+ unsigned int wwin, hwin, bwin, dwin;
+ double ratio = 1;
+ Window rootwin;
+
+ XLOCK ();;
+
+ XClearWindow (gDisplay, gXshm.window);
+
+ if(XGetGeometry(gDisplay, gXshm.window, &rootwin,
+ &xwin, &ywin, &wwin, &hwin, &bwin, &dwin) != BadDrawable) {
+
+ tmp = (wwin / 100) * 86;
+ ratio = (tmp < gXineLogoWidth && tmp >= 1) ?
+ (ratio = (double)tmp / (double)gXineLogoWidth) : 1;
+ }
+
+ resized_image = Imlib_clone_image(gImlib_data, gXineLogoImg);
+ Imlib_render (gImlib_data, resized_image,
+ (int)gXineLogoWidth * ratio,
+ (int)gXineLogoHeight * ratio);
+
+ XCopyArea (gDisplay, resized_image->pixmap, gXshm.window, gXshm.gc, 0, 0,
+ resized_image->width, resized_image->height,
+ (wwin - resized_image->width) / 2,
+ (hwin - resized_image->height) / 2);
+
+ XFlush(gDisplay);
+
+ Imlib_destroy_image(gImlib_data, resized_image);
+
+ XUNLOCK ();;
+}
+
+static void handle_event_xshm (XEvent *event) {
+
+ switch (event->type) {
+ case Expose:
+ if (event->xexpose.window == gXshm.window) {
+ if (gXshm.bLogoMode) {
+ draw_logo_xshm ();
+ } else {
+ XLOCK ();
+ XClearWindow (gDisplay, gXshm.window);
+ if (gXshm.cur_image)
+ XShmPutImage(gDisplay, gXshm.window, gXshm.gc,
+ gXshm.cur_image->mImage,
+ 0, 0, 0, 0,
+ gXshm.cur_image->mImage->width,
+ gXshm.cur_image->mImage->height, True);
+ XUNLOCK ();
+ }
+ }
+ break;
+
+ case ClientMessage:
+ if(event->xany.window == gXshm.window)
+ gui_dnd_process_client_message (gXshm.xdnd, event);
+ break;
+ }
+}
+
+static void set_logo_mode_xshm (int bLogoMode) {
+ gXshm.bLogoMode = bLogoMode;
+
+ if (bLogoMode)
+ draw_logo_xshm ();
+}
+
+static void reset_xshm () {
+
+ if (gXshm.cur_image) {
+ vo_image_drawn ( (vo_image_buffer_t *) gXshm.cur_image);
+ gXshm.cur_image = NULL;
+ }
+
+}
+
+void set_aspect_xshm (int ratio) {
+
+ ratio %= 3; /* DVB unsupported */
+
+ if (ratio != gXshm.user_ratio) {
+ gXshm.user_ratio = ratio;
+ gXshm.user_ratio_changed = 1;
+
+ set_image_format_xshm (gXshm.image_width, gXshm.image_height, gXshm.ratio, IMGFMT_YV12);
+ }
+
+ printf ("set_aspect done\n");
+}
+
+int get_aspect_xshm () {
+ return gXshm.user_ratio;
+}
+
+void exit_xshm () {
+}
+
+static int get_noop(void) {
+ return 0;
+}
+
+static int set_noop(int v) {
+ return v;
+}
+
+static vo_driver_t vo_xshm = {
+ get_capabilities_xshm,
+ set_image_format_xshm,
+ alloc_image_buffer_xshm,
+ dispose_image_buffer_xshm,
+ process_macroblock_xshm,
+ display_frame_xshm,
+ set_fullscreen_xshm,
+ is_fullscreen_xshm,
+ handle_event_xshm,
+ set_logo_mode_xshm,
+ reset_xshm,
+ display_cursor_xshm,
+ set_aspect_xshm,
+ get_aspect_xshm,
+ exit_xshm,
+
+ get_noop,
+ get_noop,
+ set_noop,
+ get_noop,
+
+ get_noop,
+ get_noop,
+ set_noop,
+ get_noop,
+
+ get_noop,
+ get_noop,
+ set_noop,
+ get_noop,
+
+ get_noop,
+ get_noop,
+ set_noop,
+ get_noop,
+
+ get_noop,
+ get_noop,
+ set_noop,
+
+ NULL,
+ NULL
+};
+
+/*
+ * connect to server, create and map window,
+ * allocate colors and (shared) memory
+ */
+
+vo_driver_t *init_video_out_xshm () {
+
+ int completionType = -1;
+ XWindowAttributes attribs;
+ int minor, major;
+ Bool bPixmaps;
+ XImage *myimage;
+ XShmSegmentInfo myshminfo;
+
+ /* XLOCK (); */
+
+ gXshm.image_width=720;
+ gXshm.image_height=576;
+
+ /*
+ * ok, X11, prepare for some video!
+ */
+
+ gXshm.screen = DefaultScreen(gDisplay);
+
+ XGetWindowAttributes(gDisplay, DefaultRootWindow(gDisplay), &attribs);
+
+ /*
+ *
+ * depth in X11 terminology land is the number of bits used to
+ * actually represent the colour.
+ *
+ * bpp in X11 land means how many bits in the frame buffer per
+ * pixel.
+ *
+ * ex. 15 bit color is 15 bit depth and 16 bpp. Also 24 bit
+ * color is 24 bit depth, but can be 24 bpp or 32 bpp.
+ */
+
+ gXshm.depth = attribs.depth;
+
+ if (gXshm.depth != 15 && gXshm.depth != 16 && gXshm.depth != 24 && gXshm.depth != 32) {
+ /* The root window may be 8bit but there might still be
+ * visuals with other bit depths. For example this is the
+ * case on Sun/Solaris machines.
+ */
+ gXshm.depth = 24;
+ }
+
+ XMatchVisualInfo(gDisplay, gXshm.screen, gXshm.depth, TrueColor, &gXshm.vinfo);
+
+ gXshm.bUseShm = 1;
+
+ /*
+ * check for X shared memory support
+ */
+
+ if (!XShmQueryExtension(gDisplay)) {
+ xprintf(VERBOSE|VIDEO, "Shared memory not supported\n\n");
+ gXshm.bUseShm = 0;
+ goto finishShmTesting;
+ }
+
+ if (!XShmQueryVersion (gDisplay, &major, &minor, &bPixmaps)){
+ xprintf(VERBOSE|VIDEO, "Shared memory not supported\n\n");
+ gXshm.bUseShm = 0;
+ goto finishShmTesting;
+ }
+
+ xprintf (VERBOSE|VIDEO, "pixmaps : %d ?= %d\n", bPixmaps, True);
+
+ if (!bPixmaps) {
+ xprintf(VERBOSE|VIDEO, "creation of shared pixmaps not possible\n\n");
+ gXshm.bUseShm = 0;
+ goto finishShmTesting;
+ }
+
+
+ completionType = XShmGetEventBase(gDisplay) + ShmCompletion;
+
+ /* try to create shared image */
+ gXshm.bFail = 0;
+ x11_InstallXErrorHandler ();
+
+ myimage = XShmCreateImage(gDisplay,
+ gXshm.vinfo.visual,
+ gXshm.vinfo.depth,
+ ZPixmap, NULL,
+ &myshminfo,
+ 100,
+ 100);
+
+ if (myimage == NULL ) {
+ xprintf(VERBOSE|VIDEO, "Shared memory error when allocating image => exit (Ximage error)\n");
+ gXshm.bUseShm = 0;
+ x11_DeInstallXErrorHandler();
+ goto finishShmTesting;
+ }
+
+ gXshm.bpp = myimage->bits_per_pixel;
+ gXshm.bytes_per_pixel = gXshm.bpp / 8;
+
+ myshminfo.shmid=shmget(IPC_PRIVATE,
+ myimage->bytes_per_line * myimage->height,
+ IPC_CREAT | 0777);
+
+ if (myshminfo.shmid < 0 ) {
+ xprintf(VERBOSE|VIDEO, "%s: allocating image \n",strerror(errno));
+ gXshm.bUseShm = 0;
+ x11_DeInstallXErrorHandler();
+ goto finishShmTesting;
+ }
+
+ myshminfo.shmaddr = (char *) shmat(myshminfo.shmid, 0, 0);
+
+ if (myshminfo.shmaddr == ((char *) -1)) {
+ xprintf(VERBOSE|VIDEO, "Shared memory error (address error) when allocating image \n");
+ gXshm.bUseShm = 0;
+ x11_DeInstallXErrorHandler();
+ goto finishShmTesting;
+ }
+
+ myshminfo.readOnly = False;
+ myimage->data = myshminfo.shmaddr;
+
+ XShmAttach(gDisplay, &myshminfo);
+
+ XSync(gDisplay, False);
+
+ if (gXshm.bFail) {
+ xprintf (VERBOSE|VIDEO, "Couldn't create shared memory image\n");
+ gXshm.bUseShm = 0;
+ x11_DeInstallXErrorHandler();
+ goto finishShmTesting;
+ }
+
+ XShmDetach (gDisplay, &myshminfo);
+ XDestroyImage (myimage);
+ shmdt (myshminfo.shmaddr);
+ shmctl (myshminfo.shmid, IPC_RMID, 0);
+
+ x11_DeInstallXErrorHandler();
+
+ finishShmTesting:
+
+ if (!gXshm.bUseShm) {
+ printf ("\n\n!!! failed to initialize X shared memory extension. Fall back to plain X11 functions. This is very slow and mostly untested. Are you sure you're using a local graphics device for output? Remote playing via network is not supported by xine!!!\n\n");
+ }
+
+
+ /*
+ * init global variables
+ */
+
+ gXshm.bFullscreen = 0;
+ gXshm.bIsFullscreen = 0;
+ gXshm.ratio = 0;
+ gXshm.user_ratio = ASPECT_AUTO;
+ gXshm.user_ratio_changed = 0 ;
+ gXshm.bLogoMode = 1;
+ gXshm.bYuvInitialized = 0;
+ gXshm.cur_image = NULL;
+
+ set_image_format_xshm (720,576,1,IMGFMT_YV12);
+
+ create_cursor_xshm(DefaultColormap(gDisplay, 0));
+ gXshm.current_cursor = SHOW_CURSOR;
+
+ /*
+ * If gVo.depth is 24 then it may either be a 3 or 4 byte per pixel
+ * format. We can't use bpp because then we would lose the
+ * distinction between 15/16bit gVo.depth (2 byte formate assumed).
+ *
+ * FIXME - change yuv2rgb_init to take both gVo.depth and bpp
+ * parameters
+ */
+
+ if (gXshm.depth>16)
+ printf ("\n\nWARNING: current display depth is %d. For better performance\na depth of 16 bpp is recommended!\n\n",
+ gXshm.depth);
+
+ /* yuv2rgb_init((gXshm.depth == 24) ? gXshm.bpp : gXshm.depth,MODE_RGB); */
+
+ /* XUNLOCK (); */
+
+ return &vo_xshm;
+}
diff --git a/src/video_out/video_out_xv.c b/src/video_out/video_out_xv.c
new file mode 100644
index 000000000..00cc8c18d
--- /dev/null
+++ b/src/video_out/video_out_xv.c
@@ -0,0 +1,903 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: video_out_xv.c,v 1.1 2001/04/24 20:53:00 f1rmb Exp $
+ *
+ * video_out_xv.c, X11 video extension interface for xine
+ *
+ * based on mpeg2dec code from
+ * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * Xv image support by Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ * xine-specific code by Guenter Bartsch <bartscgr@studbox.uni-stuttgart.de>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_XV
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/Xv.h>
+#include <X11/extensions/Xvlib.h>
+#ifdef HAVE_XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "video_out.h"
+
+/* override xprintf definition */
+#define xprintf(LVL, FMT, ARGS...) { printf(FMT, ##ARGS); }
+
+typedef struct xv_property_s {
+ int value;
+ int min;
+ int max;
+ Atom atom;
+ char *key;
+} xv_property_t;
+
+typedef struct xv_frame_s {
+ vo_frame_t vo_frame;
+
+ int width, height, ratio_code, format;
+
+ XvImage *image;
+ XShmSegmentInfo shminfo;
+
+} xv_frame_t;
+
+typedef struct xv_driver_s {
+
+ vo_driver_t vo_driver;
+
+ config_values_t *config;
+
+ /* X11 / Xv related stuff */
+ Display *display;
+ int screen;
+ unsigned int xv_format_rgb, xv_format_yv12, xv_format_yuy2;
+ int depth;
+ XColor black;
+ XVisualInfo vinfo;
+ Window window;
+ XClassHint *xclasshint;
+ GC gc;
+ int CompletionType;
+ unsigned int xv_port;
+
+ xv_property_t props[VO_NUM_PROPERTIES];
+ uint32_t capabilities;
+
+ xv_frame_t *cur_frame;
+
+ /* size / aspect ratio calculations */
+ int delivered_width; /* everything is set up for these frame dimensions */
+ int delivered_height; /* the dimension as they come from the decoder */
+ int delivered_ratio_code;
+ double ratio_factor; /* output frame must fullfill: height = width * ratio_factor */
+ int output_width; /* frames will appear in this size (pixels) on screen */
+ int output_height;
+ int output_xoffset;
+ int output_yoffset;
+
+ /* display anatomy */
+ double display_ratio; /* calced from display resolution */
+ int fullscreen_width; /* this is basically how big the screen is */
+ int fullscreen_height;
+ int in_fullscreen; /* is the window in fullscreen mode? */
+} xv_driver_t;
+
+
+static uint32_t xv_get_capabilities (vo_driver_t *this_gen) {
+
+ xv_driver_t *this = (xv_driver_t *) this_gen;
+
+ return this->capabilities;
+}
+
+static vo_frame_t *xv_alloc_frame (vo_driver_t *this_gen) {
+
+ xv_frame_t *frame ;
+
+ frame = (xv_frame_t *) malloc (sizeof (xv_frame_t));
+ memset (frame, 0, sizeof(xv_frame_t));
+
+ if (frame==NULL) {
+ printf ("xv_alloc_frame: out of memory\n");
+ }
+
+ pthread_mutex_init (&frame->vo_frame.mutex, NULL);
+
+ return (vo_frame_t *) frame;
+}
+
+static void xv_update_frame_format (vo_driver_t *this_gen, vo_frame_t *frame_gen,
+ uint32_t width, uint32_t height, int ratio_code,
+ int format) {
+
+ xv_driver_t *this = (xv_driver_t *) this_gen;
+ xv_frame_t *frame = (xv_frame_t *) frame_gen;
+ unsigned int xv_format;
+
+ if ((frame->width != width) || (frame->height != height) || (frame->format != format)) {
+
+ XLockDisplay (this->display);
+
+ /*
+ * (re-) allocate xvimage
+ */
+
+ if (frame->image) {
+ XShmDetach (this->display, &frame->shminfo);
+
+ XFree (frame->image);
+ shmdt (frame->shminfo.shmaddr);
+ shmctl (frame->shminfo.shmid, IPC_RMID,NULL);
+
+ frame->image = NULL;
+ }
+
+ switch (format) {
+ case IMGFMT_YV12:
+ xv_format = this->xv_format_yv12;
+ break;
+ case IMGFMT_RGB:
+ xv_format = this->xv_format_rgb;
+ break;
+ case IMGFMT_YUY2:
+ xv_format = this->xv_format_yuy2;
+ break;
+ default:
+ fprintf (stderr, "xv_update_frame_format: unknown format %08x\n",format);
+ exit (1);
+ }
+
+ frame->image = XvShmCreateImage(this->display, this->xv_port, xv_format, 0,
+ width, height, &frame->shminfo);
+
+ if (frame->image == NULL ) {
+ fprintf(stderr, "xv_image_format: XvShmCreateImage failed.\n");
+ exit (1);
+ }
+
+ frame->shminfo.shmid=shmget(IPC_PRIVATE,
+ frame->image->data_size,
+ IPC_CREAT | 0777);
+
+ if (frame->image->data_size==0) {
+ fprintf(stderr, "xv_update_frame_format: XvShmCreateImage returned a zero size\n");
+ exit (1);
+ }
+
+ if (frame->shminfo.shmid < 0 ) {
+ perror("xv_update_frame_format: shared memory error in shmget: ");
+ exit (1);
+ }
+
+ frame->shminfo.shmaddr = (char *) shmat(frame->shminfo.shmid, 0, 0);
+
+ if (frame->shminfo.shmaddr == NULL) {
+ fprintf(stderr, "xv_update_frame_format: shared memory error (address error NULL)\n");
+ exit (1);
+ }
+
+ if (frame->shminfo.shmaddr == ((char *) -1)) {
+ fprintf(stderr, "xv_update_frame_format: shared memory error (address error)\n");
+ exit (1);
+ }
+
+ frame->shminfo.readOnly = False;
+ frame->image->data = frame->shminfo.shmaddr;
+
+ XShmAttach(this->display, &frame->shminfo);
+
+ XSync(this->display, False);
+ shmctl(frame->shminfo.shmid, IPC_RMID, 0);
+
+ frame->vo_frame.base[0] = frame->image->data;
+ frame->vo_frame.base[1] = frame->image->data + width * height * 5 / 4;
+ frame->vo_frame.base[2] = frame->image->data + width * height;
+
+ frame->width = width;
+ frame->height = height;
+ frame->format = format;
+
+ XUnlockDisplay (this->display);
+ }
+
+ frame->ratio_code = ratio_code;
+}
+
+static void xv_calc_format (xv_driver_t *this, int width, int height, int ratio_code) {
+
+ double image_ratio, desired_ratio;
+
+ this->delivered_width = width;
+ this->delivered_height = height;
+ this->delivered_ratio_code = ratio_code;
+
+ /*
+ * aspect ratio calculation
+ */
+
+ image_ratio = (double) this->delivered_width / (double) this->delivered_height;
+
+ xprintf (VERBOSE | VIDEO, "display_ratio : %f\n",this->display_ratio);
+ xprintf (VERBOSE | VIDEO, "stream aspect ratio : %f , code : %d\n", image_ratio, ratio_code);
+
+ switch (this->props[VO_PROP_ASPECT_RATIO].value) {
+ case ASPECT_AUTO:
+ switch (ratio_code) {
+ case 3: /* anamorphic */
+ desired_ratio = 16.0 /9.0;
+ break;
+ case 42: /* probably non-mpeg stream => don't touch aspect ratio */
+ desired_ratio = image_ratio;
+ break;
+ case 0: /* forbidden */
+ fprintf (stderr, "invalid ratio, using 4:3\n");
+ case 1: /* "square" => 4:3 */
+ case 2: /* 4:3 */
+ default:
+ xprintf (VIDEO, "unknown aspect ratio (%d) in stream => using 4:3\n", ratio_code);
+ desired_ratio = 4.0 / 3.0;
+ break;
+ }
+ break;
+ case ASPECT_ANAMORPHIC:
+ desired_ratio = 16.0 / 9.0;
+ break;
+ case ASPECT_DVB:
+ desired_ratio = 2.0 / 1.0;
+ break;
+ default:
+ desired_ratio = 4.0 / 3.0;
+ }
+
+ /* this->ratio_factor = display_ratio * desired_ratio / image_ratio ; */
+ this->ratio_factor = this->display_ratio * desired_ratio;
+
+
+ /*
+ * calc output frame size
+ */
+
+ if (this->props[VO_PROP_FULLSCREEN].value) {
+
+ if ( ((double) this->fullscreen_width / this->ratio_factor) < this->fullscreen_height ) {
+
+ this->output_width = this->fullscreen_width ;
+ this->output_height = (double) this->fullscreen_width / this->ratio_factor ;
+ this->output_xoffset = 0;
+ this->output_yoffset = (this->fullscreen_height - this->output_height) / 2;
+
+ } else {
+
+ this->output_width = (double) this->fullscreen_height * this->ratio_factor ;
+ this->output_height = this->fullscreen_height;
+ this->output_xoffset = (this->fullscreen_width - this->output_width) / 2;
+ this->output_yoffset = 0;
+ }
+
+ } else {
+
+ double corr_factor = this->ratio_factor / image_ratio ;
+
+
+ if (corr_factor >= 1.0) {
+ this->output_width = this->delivered_width * corr_factor;
+ this->output_height = this->delivered_height ;
+ }
+ else {
+ this->output_width = this->delivered_width;
+ this->output_height = this->delivered_height / corr_factor;
+ }
+
+ /* little hack to zoom mpeg1 / other small streams by default*/
+ if (this->output_width<600) {
+ this->output_width *=2;
+ this->output_height *=2;
+ }
+
+ this->output_xoffset = 0;
+ this->output_yoffset = 0;
+ }
+}
+
+typedef struct
+{
+ int flags;
+ int functions;
+ int decorations;
+ int input_mode;
+ int status;
+} MWMHints;
+
+#define MWM_HINTS_DECORATIONS (1L << 1)
+#define PROP_MWM_HINTS_ELEMENTS 5
+
+static void xv_setup_window (xv_driver_t *this) {
+
+ static char *window_title = "xine Xv video output";
+ XSizeHints hint;
+ XWMHints *wm_hint;
+ XSetWindowAttributes attr;
+ Atom prop;
+ Atom wm_delete_window;
+ MWMHints mwmhints;
+ XEvent xev;
+ XGCValues xgcv;
+
+ XLockDisplay (this->display);
+
+ if (this->props[VO_PROP_FULLSCREEN].value) {
+
+ if (this->window) {
+
+ if (this->in_fullscreen) {
+ XUnlockDisplay (this->display);
+ return;
+ }
+
+ XDestroyWindow(this->display, this->window);
+ this->window = 0;
+
+ }
+
+ this->in_fullscreen = 1;
+
+ /*
+ * open fullscreen window
+ */
+
+ attr.background_pixel = this->black.pixel;
+
+ this->window = XCreateWindow (this->display, RootWindow (this->display, this->screen),
+ 0, 0, this->fullscreen_width, this->fullscreen_height,
+ 0, this->depth, CopyFromParent, this->vinfo.visual,
+ CWBackPixel, &attr);
+
+ if (this->xclasshint != NULL)
+ XSetClassHint(this->display, this->window, this->xclasshint);
+
+ /*
+ * wm, no borders please
+ */
+
+ prop = XInternAtom(this->display, "_MOTIF_WM_HINTS", False);
+ mwmhints.flags = MWM_HINTS_DECORATIONS;
+ mwmhints.decorations = 0;
+ XChangeProperty(this->display, this->window, prop, prop, 32,
+ PropModeReplace, (unsigned char *) &mwmhints,
+ PROP_MWM_HINTS_ELEMENTS);
+ XSetTransientForHint(this->display, this->window, None);
+ XRaiseWindow(this->display, this->window);
+
+ } else {
+
+ if (this->window) {
+
+ if (this->in_fullscreen) {
+ XDestroyWindow(this->display, this->window);
+ this->window = 0;
+ } else {
+
+ XResizeWindow (this->display, this->window,
+ this->output_width, this->output_height);
+
+ XUnlockDisplay (this->display);
+
+ return;
+
+ }
+ }
+
+ this->in_fullscreen = 0;
+
+ hint.x = 0;
+ hint.y = 0;
+ hint.width = this->output_width;
+ hint.height = this->output_height;
+ hint.flags = PPosition | PSize;
+
+ /*
+ theCmap = XCreateColormap(gDisplay, RootWindow(gDisplay,gXv.screen),
+ gXv.vinfo.visual, AllocNone); */
+
+ attr.background_pixel = this->black.pixel;
+ attr.border_pixel = 1;
+ /* attr.colormap = theCmap; */
+
+
+ this->window = XCreateWindow(this->display, RootWindow(this->display, this->screen),
+ hint.x, hint.y, hint.width, hint.height, 4,
+ this->depth, CopyFromParent, this->vinfo.visual,
+ CWBackPixel | CWBorderPixel , &attr);
+
+ if (this->xclasshint != NULL)
+ XSetClassHint(this->display, this->window, this->xclasshint);
+
+
+ /* Tell other applications about this window */
+
+ XSetStandardProperties(this->display, this->window, window_title, window_title,
+ None, NULL, 0, &hint);
+
+ }
+
+ XSelectInput(this->display, this->window, StructureNotifyMask | ExposureMask | KeyPressMask | ButtonPressMask);
+
+ wm_hint = XAllocWMHints();
+ if (wm_hint != NULL) {
+ wm_hint->input = True;
+ wm_hint->initial_state = NormalState;
+ wm_hint->flags = InputHint | StateHint;
+ XSetWMHints(this->display, this->window, wm_hint);
+ XFree(wm_hint);
+ }
+
+ wm_delete_window = XInternAtom(this->display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(this->display, this->window, &wm_delete_window, 1);
+
+ /* Map window. */
+
+ XMapRaised(this->display, this->window);
+
+ /* Wait for map. */
+
+ do {
+ XMaskEvent(this->display,
+ StructureNotifyMask,
+ &xev) ;
+ } while (xev.type != MapNotify || xev.xmap.event != this->window);
+
+ XFlush(this->display);
+ XSync(this->display, False);
+
+ this->gc = XCreateGC(this->display, this->window, 0L, &xgcv);
+
+ if (this->in_fullscreen) {
+ XSetInputFocus (this->display, this->window, RevertToNone, CurrentTime);
+ XMoveWindow (this->display, this->window, 0, 0);
+ }
+
+ XUnlockDisplay (this->display);
+
+ /* drag and drop FIXME: move this to the GUI */
+
+ /*
+ if(!gXv.xdnd)
+ gXv.xdnd = (DND_struct_t *) malloc(sizeof(DND_struct_t));
+
+ gui_init_dnd(gXv.xdnd);
+ gui_dnd_set_callback (gXv.xdnd, gui_dndcallback);
+ gui_make_window_dnd_aware (gXv.xdnd, gXv.window);
+ */
+
+ /*
+ * make cursor disappear
+ */
+
+ /* FIXME: implement in a clean way
+
+ Cursor not already created.
+ if(gXv.current_cursor == -1) {
+ create_cursor_xv(theCmap);
+ gXv.current_cursor = SHOW_CURSOR;
+ };
+ */
+}
+
+static void xv_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) {
+
+ xv_driver_t *this = (xv_driver_t *) this_gen;
+ xv_frame_t *frame = (xv_frame_t *) frame_gen;
+
+ if ( (frame->width != this->delivered_width) || (frame->height != this->delivered_height)
+ || (frame->ratio_code != this->delivered_ratio_code) ) {
+
+ xv_calc_format (this, frame->width, frame->height, frame->ratio_code);
+ xv_setup_window (this);
+ }
+
+ XLockDisplay (this->display);
+
+ XvShmPutImage(this->display, this->xv_port, this->window, this->gc, frame->image,
+ 0, 0, frame->width, frame->height,
+ this->output_xoffset, this->output_yoffset,
+ this->output_width, this->output_height, False);
+
+
+ XFlush(this->display);
+
+ XUnlockDisplay (this->display);
+
+ /* FIXME: this should be done using the completion event */
+ if (this->cur_frame) {
+ this->cur_frame->vo_frame.displayed (&this->cur_frame->vo_frame);
+ }
+
+ this->cur_frame = frame;
+}
+
+static int xv_get_property (vo_driver_t *this_gen, int property) {
+
+ xv_driver_t *this = (xv_driver_t *) this_gen;
+
+ return this->props[property].value;
+
+}
+
+static int xv_set_property (vo_driver_t *this_gen,
+ int property, int value) {
+
+ xv_driver_t *this = (xv_driver_t *) this_gen;
+
+ if (this->props[property].atom) {
+ XvSetPortAttribute (this->display, this->xv_port,
+ this->props[property].atom, value);
+ XvGetPortAttribute (this->display, this->xv_port,
+ this->props[property].atom,
+ &this->props[property].value);
+
+ this->config->set_int (this->config, this->props[property].key,
+ this->props[property].value);
+
+ return this->props[property].value;
+ } else {
+ /* FIXME: implement these props
+ switch (property) {
+ case VO_PROP_WINDOW_VISIBLE:
+ break;
+ case VO_PROP_CURSOR_VISIBLE:
+ break;
+ case VO_PROP_FULLSCREEN:
+ break;
+ case VO_PROP_INTERLACED:
+ break;
+ case VO_PROP_ASPECT_RATIO:
+ break;
+ }
+ */
+ }
+
+ return value;
+}
+
+static void xv_get_property_min_max (vo_driver_t *this_gen,
+ int property, int *min, int *max) {
+
+ xv_driver_t *this = (xv_driver_t *) this_gen;
+
+ *min = this->props[property].min;
+ *max = this->props[property].max;
+}
+
+static void xv_handle_event (vo_driver_t *this_gen, void *event_gen) {
+
+ /* FIXME: implement */
+
+}
+
+static void* xv_get_window (vo_driver_t *this_gen) {
+ xv_driver_t *this = (xv_driver_t *) this_gen;
+
+ return &this->window;
+}
+
+static void xv_set_logo_mode (vo_driver_t *this_gen, int show_logo) {
+
+ /* FIXME: implement */
+}
+
+static void xv_exit (vo_driver_t *this_gen) {
+
+ xv_driver_t *this = (xv_driver_t *) this_gen;
+
+ if(XvUngrabPort (this->display, this->xv_port, CurrentTime) != Success) {
+ fprintf(stderr, "xv_exit: XvUngrabPort() failed.\n");
+ }
+}
+
+static int xv_check_yv12 (Display *display, XvPortID port)
+{
+ XvImageFormatValues * formatValues;
+ int formats;
+ int i;
+
+ formatValues = XvListImageFormats (display, port, &formats);
+ for (i = 0; i < formats; i++)
+ if ((formatValues[i].id == IMGFMT_YV12) &&
+ (! (strcmp (formatValues[i].guid, "YV12")))) {
+ XFree (formatValues);
+ return 0;
+ }
+ XFree (formatValues);
+ return 1;
+}
+
+static void xv_check_capability (xv_driver_t *this, uint32_t capability, int property,
+ XvAttribute attr, int base_id, char *str_prop) {
+
+ int nDefault;
+
+ this->capabilities |= capability;
+ this->props[property].min = attr.min_value;
+ this->props[property].max = attr.max_value;
+ this->props[property].atom = XInternAtom (this->display, str_prop, False);
+ this->props[property].key = str_prop;
+
+ XvGetPortAttribute (this->display, this->xv_port, this->props[property].atom, &nDefault);
+
+ xv_set_property (&this->vo_driver, property, this->config->lookup_int (this->config, str_prop, nDefault) );
+}
+
+vo_driver_t *init_video_out_xv (Display *display, config_values_t *config) {
+
+ xv_driver_t *this;
+ unsigned int adaptor_num, adaptors, i, j, formats;
+ unsigned int ver,rel,req,ev,err;
+ unsigned int xv_port;
+ XvAttribute *attr;
+ XvAdaptorInfo *adaptor_info;
+ XvImageFormatValues *fo;
+ int nattr;
+ double res_h, res_v;
+ XColor ignored;
+ XWindowAttributes attribs;
+ int dummy_a, dummy_b;
+#ifdef HAVE_XINERAMA
+ int screens;
+ XineramaScreenInfo *screeninfo = NULL;
+#endif
+
+ /*
+ * check for Xvideo support
+ */
+
+ if (Success != XvQueryExtension(display,&ver,&rel,&req,&ev,&err)) {
+ printf ("video_out_xv: Xv extension not present.\n");
+ return NULL;
+ }
+
+ /*
+ * check adaptors, search for one that supports (at least) yuv12
+ */
+
+ if (Success != XvQueryAdaptors(display,DefaultRootWindow(display),
+ &adaptors,&adaptor_info)) {
+ printf("video_out_xv: XvQueryAdaptors failed.\n");
+ return NULL;
+ }
+
+ xv_port = 0;
+ adaptor_num = 0;
+
+ while ( (adaptor_num < adaptors) && !xv_port) {
+ if (adaptor_info[adaptor_num].type & XvImageMask)
+ for (j = 0; j < adaptor_info[adaptor_num].num_ports; j++)
+ if (( !(xv_check_yv12 (display, adaptor_info[adaptor_num].base_id + j)))
+ && (XvGrabPort (display, adaptor_info[adaptor_num].base_id + j, 0) == Success)) {
+ xv_port = adaptor_info[adaptor_num].base_id + j;
+ break;
+ }
+
+ adaptor_num++;
+ }
+
+ if (!xv_port) {
+ printf ("video_out_xv: Xv extension is present but I couldn't find a usable yuv12 port.\n");
+ printf (" Looks like your graphics hardware driver doesn't support Xv?!\n");
+ XvFreeAdaptorInfo (adaptor_info);
+ return NULL;
+ } else
+ printf ("video_out_xv: using Xv port %d for hardware colorspace conversion and scaling.\n", xv_port);
+
+
+ /*
+ * from this point on, nothing should go wrong anymore; so let's start initializing this driver
+ */
+
+ this = malloc (sizeof (xv_driver_t));
+ memset (this, 0, sizeof(xv_driver_t));
+
+ this->display = display;
+ this->screen = DefaultScreen(display);
+ this->xv_port = xv_port;
+ this->capabilities = 0;
+ this->config = config;
+
+ this->vo_driver.get_capabilities = xv_get_capabilities;
+ this->vo_driver.alloc_frame = xv_alloc_frame;
+ this->vo_driver.update_frame_format = xv_update_frame_format;
+ this->vo_driver.display_frame = xv_display_frame;
+ this->vo_driver.get_property = xv_get_property;
+ this->vo_driver.set_property = xv_set_property;
+ this->vo_driver.get_property_min_max = xv_get_property_min_max;
+ this->vo_driver.handle_event = xv_handle_event;
+ this->vo_driver.get_window = xv_get_window;
+ this->vo_driver.set_logo_mode = xv_set_logo_mode;
+ this->vo_driver.exit = xv_exit;
+
+ if (XAllocNamedColor (display, DefaultColormap (display, this->screen),
+ "black", &this->black, &ignored) == 0) {
+ fprintf (stderr, "video_out_xv: cannot allocate color black\n");
+ exit(1);
+ }
+
+ XGetWindowAttributes(display, DefaultRootWindow(display), &attribs);
+
+ this->depth = attribs.depth;
+
+ if (this->depth != 15 && this->depth != 16 && this->depth != 24 && this->depth != 32) {
+ /* The root window may be 8bit but there might still be
+ * visuals with other bit depths. For example this is the
+ * case on Sun/Solaris machines.
+ */
+ this->depth = 24;
+ }
+
+ XMatchVisualInfo(display, this->screen, this->depth, TrueColor, &this->vinfo);
+
+ /*
+ * init properties
+ */
+
+ for (i=0; i<VO_NUM_PROPERTIES; i++) {
+ this->props[i].value = 0;
+ this->props[i].min = 0;
+ this->props[i].max = 0;
+ this->props[i].atom = 0;
+ }
+
+ this->props[VO_PROP_WINDOW_VISIBLE].value = 1;
+ this->props[VO_PROP_CURSOR_VISIBLE].value = 1;
+ this->props[VO_PROP_FULLSCREEN].value = 0;
+ this->props[VO_PROP_INTERLACED].value = 0;
+ this->props[VO_PROP_ASPECT_RATIO].value = ASPECT_AUTO;
+
+ /*
+ * check this adaptor's capabilities
+ */
+
+ attr = XvQueryPortAttributes(display, adaptor_info[i].base_id, &nattr);
+ if(attr && nattr) {
+ int k;
+
+ for(k = 0; k < nattr; k++) {
+
+ if(attr[k].flags & XvSettable) {
+ if(!strcmp(attr[k].name, "XV_HUE"))
+ xv_check_capability (this, VO_CAP_HUE, VO_PROP_HUE, attr[k],
+ adaptor_info[i].base_id, "XV_HUE");
+ else if(!strcmp(attr[k].name, "XV_SATURATION"))
+ xv_check_capability (this, VO_CAP_SATURATION, VO_PROP_SATURATION, attr[k],
+ adaptor_info[i].base_id, "XV_SATURATION");
+ else if(!strcmp(attr[k].name, "XV_BRIGHTNESS"))
+ xv_check_capability (this, VO_CAP_BRIGHTNESS, VO_PROP_BRIGHTNESS, attr[k],
+ adaptor_info[i].base_id, "XV_BRIGHTNESS");
+ else if(!strcmp(attr[k].name, "XV_CONTRAST"))
+ xv_check_capability (this, VO_CAP_CONTRAST, VO_PROP_CONTRAST, attr[k],
+ adaptor_info[i].base_id, "XV_CONTRAST");
+ else if(!strcmp(attr[k].name, "XV_COLORKEY"))
+ xv_check_capability (this, VO_CAP_COLORKEY, VO_PROP_COLORKEY, attr[k],
+ adaptor_info[i].base_id, "XV_COLORKEY");
+ }
+
+ XFree(attr);
+ }
+ } else {
+ printf("video_out_xv: no port attributes defined.\n");
+ }
+
+ XvFreeAdaptorInfo (adaptor_info);
+
+ /*
+ * check supported image formats
+ */
+
+ fo = XvListImageFormats(display, this->xv_port, (int*)&formats);
+
+ this->xv_format_yv12 = 0;
+ this->xv_format_yuy2 = 0;
+ this->xv_format_rgb = 0;
+
+ for(i = 0; i < formats; i++) {
+ xprintf(VERBOSE|VIDEO, "video_out_xv: Xv image format: 0x%x (%4.4s) %s\n",
+ fo[i].id, (char*)&fo[i].id,
+ (fo[i].format == XvPacked) ? "packed" : "planar");
+ if (fo[i].id == IMGFMT_YV12) {
+ this->xv_format_yv12 = fo[i].id;
+ this->capabilities |= VO_CAP_YV12;
+ printf ("video_out_xv: this adaptor supports the yv12 format.\n");
+ } else if (fo[i].id == IMGFMT_YUY2) {
+ this->xv_format_yuy2 = fo[i].id;
+ this->capabilities |= VO_CAP_YUY2;
+ printf ("video_out_xv: this adaptor supports the yuy2 format.\n");
+ } else if (fo[i].id == IMGFMT_RGB) {
+ this->xv_format_rgb = fo[i].id;
+ this->capabilities |= VO_CAP_RGB;
+ printf ("video_out_xv: this adaptor supports the rgb format.\n");
+ }
+ }
+
+ /*
+ * find out screen dimensions
+ */
+
+#ifdef HAVE_XINERAMA
+ /* Spark
+ * some Xinerama stuff
+ * I want to figure out what fullscreen means for this setup
+ */
+
+ if ((XineramaQueryExtension (display, &dummy_a, &dummy_b))
+ && (screeninfo = XineramaQueryScreens(display, &screens))) {
+ /* Xinerama Detected */
+ xprintf (VERBOSE|VIDEO,
+ "Display is using Xinerama with %d screens\n", screens);
+ xprintf (VERBOSE|VIDEO,
+ " going to assume we are using the first screen.\n");
+ xprintf (VERBOSE|VIDEO, " size of the first screen is %dx%d.\n",
+ screeninfo[0].width, screeninfo[0].height);
+
+ if (XineramaIsActive(display)) {
+ this->fullscreen_width = screeninfo[0].width;
+ this->fullscreen_height = screeninfo[0].height;
+ } else {
+ this->fullscreen_width = DisplayWidth (display, this->screen);
+ this->fullscreen_height = DisplayHeight (display, this->screen);
+ }
+
+ } else {
+ /* no Xinerama */
+ xprintf (VERBOSE|VIDEO, "Display is not using Xinerama.\n");
+ }
+#else
+ this->fullscreen_width = DisplayWidth (display, this->screen);
+ this->fullscreen_height = DisplayHeight (display, this->screen);
+#endif
+
+ res_h = (this->fullscreen_width*1000 / DisplayWidthMM (display, this->screen));
+ res_v = (this->fullscreen_height*1000 / DisplayHeightMM (display, this->screen));
+ this->display_ratio = res_h / res_v;
+
+ /*
+ * init window
+ */
+
+ xv_calc_format (this, 720, 576, 2);
+ xv_setup_window (this);
+
+ return &this->vo_driver;
+}
+
+#endif
diff --git a/src/video_out/yuv2rgb.c b/src/video_out/yuv2rgb.c
new file mode 100644
index 000000000..05af7a88b
--- /dev/null
+++ b/src/video_out/yuv2rgb.c
@@ -0,0 +1,465 @@
+/*
+ * yuv2rgb.c
+ * Copyright (C) 1999-2001 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ *
+ * mpeg2dec is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mpeg2dec is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include "yuv2rgb.h"
+#include "attributes.h"
+#include "cpu_accel.h"
+#include "utils.h"
+
+
+const int32_t Inverse_Table_6_9[8][4] = {
+ {117504, 138453, 13954, 34903}, /* no sequence_display_extension */
+ {117504, 138453, 13954, 34903}, /* ITU-R Rec. 709 (1990) */
+ {104597, 132201, 25675, 53279}, /* unspecified */
+ {104597, 132201, 25675, 53279}, /* reserved */
+ {104448, 132798, 24759, 53109}, /* FCC */
+ {104597, 132201, 25675, 53279}, /* ITU-R Rec. 624-4 System B, G */
+ {104597, 132201, 25675, 53279}, /* SMPTE 170M */
+ {117579, 136230, 16907, 35559} /* SMPTE 240M (1987) */
+};
+
+static void yuv2rgb_c (yuv2rgb_t *this, uint8_t *image,
+ uint8_t *py, uint8_t *pu, uint8_t *pv) {
+
+ /* int dy = this->step_dy; */
+ int height = this->source_height >>= 1;
+
+ do {
+ this->yuv2rgb_c_internal (this, py, py + this->y_stride, pu, pv,
+ image, ((uint8_t *)image) + this->rgb_stride,
+ this->source_width);
+
+ py += 2 * this->y_stride;
+ pu += this->uv_stride;
+ pv += this->uv_stride;
+ image = ((uint8_t *) image) + 2 * this->rgb_stride;
+ } while (--height);
+}
+
+int yuv2rgb_setup (yuv2rgb_t *this,
+ int source_width, int source_height,
+ int y_stride, int uv_stride,
+ int dest_width, int dest_height,
+ int rgb_stride) {
+
+
+ this->source_width = source_width;
+ this->source_height = source_height;
+ this->y_stride = y_stride;
+ this->uv_stride = uv_stride;
+ this->dest_width = dest_width;
+ this->dest_height = dest_height;
+ this->rgb_stride = rgb_stride;
+
+ if ((source_width == dest_width) && (source_height == dest_height))
+ this->do_scale = 0;
+ else {
+ this->do_scale = 1;
+
+ this->step_dx = source_width * 32768 / dest_width;
+ this->step_dy = source_height * 32768 / dest_height;
+
+ if (this->y_buffer) free (this->y_buffer);
+ if (this->u_buffer) free (this->u_buffer);
+ if (this->v_buffer) free (this->v_buffer);
+
+ this->y_buffer = xmalloc_aligned (16, dest_width);
+ if (!this->y_buffer)
+ return 0;
+ this->u_buffer = xmalloc_aligned (16, dest_width);
+ if (!this->u_buffer)
+ return 0;
+ this->v_buffer = xmalloc_aligned (16, dest_width);
+ if (!this->v_buffer)
+ return 0;
+ }
+ return 1;
+}
+
+
+#define RGB(i) \
+ U = pu[i]; \
+ V = pv[i]; \
+ r = this->table_rV[V]; \
+ g = (void *) (((uint8_t *)this->table_gU[U]) + this->table_gV[V]); \
+ b = this->table_bU[U];
+
+#define DST1(i) \
+ Y = py_1[2*i]; \
+ dst_1[2*i] = r[Y] + g[Y] + b[Y]; \
+ Y = py_1[2*i+1]; \
+ dst_1[2*i+1] = r[Y] + g[Y] + b[Y];
+
+#define DST2(i) \
+ Y = py_2[2*i]; \
+ dst_2[2*i] = r[Y] + g[Y] + b[Y]; \
+ Y = py_2[2*i+1]; \
+ dst_2[2*i+1] = r[Y] + g[Y] + b[Y];
+
+#define DST1RGB(i) \
+ Y = py_1[2*i]; \
+ dst_1[6*i] = r[Y]; dst_1[6*i+1] = g[Y]; dst_1[6*i+2] = b[Y]; \
+ Y = py_1[2*i+1]; \
+ dst_1[6*i+3] = r[Y]; dst_1[6*i+4] = g[Y]; dst_1[6*i+5] = b[Y];
+
+#define DST2RGB(i) \
+ Y = py_2[2*i]; \
+ dst_2[6*i] = r[Y]; dst_2[6*i+1] = g[Y]; dst_2[6*i+2] = b[Y]; \
+ Y = py_2[2*i+1]; \
+ dst_2[6*i+3] = r[Y]; dst_2[6*i+4] = g[Y]; dst_2[6*i+5] = b[Y];
+
+#define DST1BGR(i) \
+ Y = py_1[2*i]; \
+ dst_1[6*i] = b[Y]; dst_1[6*i+1] = g[Y]; dst_1[6*i+2] = r[Y]; \
+ Y = py_1[2*i+1]; \
+ dst_1[6*i+3] = b[Y]; dst_1[6*i+4] = g[Y]; dst_1[6*i+5] = r[Y];
+
+#define DST2BGR(i) \
+ Y = py_2[2*i]; \
+ dst_2[6*i] = b[Y]; dst_2[6*i+1] = g[Y]; dst_2[6*i+2] = r[Y]; \
+ Y = py_2[2*i+1]; \
+ dst_2[6*i+3] = b[Y]; dst_2[6*i+4] = g[Y]; dst_2[6*i+5] = r[Y];
+
+static void yuv2rgb_c_32 (yuv2rgb_t *this,
+ uint8_t * py_1, uint8_t * py_2,
+ uint8_t * pu, uint8_t * pv,
+ void * _dst_1, void * _dst_2, int width)
+{
+ int U, V, Y;
+ uint32_t * r, * g, * b;
+ uint32_t * dst_1, * dst_2;
+
+ width >>= 3;
+ dst_1 = _dst_1;
+ dst_2 = _dst_2;
+
+ do {
+ RGB(0);
+ DST1(0);
+ DST2(0);
+
+ RGB(1);
+ DST2(1);
+ DST1(1);
+
+ RGB(2);
+ DST1(2);
+ DST2(2);
+
+ RGB(3);
+ DST2(3);
+ DST1(3);
+
+ pu += 4;
+ pv += 4;
+ py_1 += 8;
+ py_2 += 8;
+ dst_1 += 8;
+ dst_2 += 8;
+ } while (--width);
+}
+
+/* This is very near from the yuv2rgb_c_32 code */
+static void yuv2rgb_c_24_rgb (yuv2rgb_t *this,
+ uint8_t * py_1, uint8_t * py_2,
+ uint8_t * pu, uint8_t * pv,
+ void * _dst_1, void * _dst_2, int width)
+{
+ int U, V, Y;
+ uint8_t * r, * g, * b;
+ uint8_t * dst_1, * dst_2;
+
+ width >>= 3;
+ dst_1 = _dst_1;
+ dst_2 = _dst_2;
+
+ do {
+ RGB(0);
+ DST1RGB(0);
+ DST2RGB(0);
+
+ RGB(1);
+ DST2RGB(1);
+ DST1RGB(1);
+
+ RGB(2);
+ DST1RGB(2);
+ DST2RGB(2);
+
+ RGB(3);
+ DST2RGB(3);
+ DST1RGB(3);
+
+ pu += 4;
+ pv += 4;
+ py_1 += 8;
+ py_2 += 8;
+ dst_1 += 24;
+ dst_2 += 24;
+ } while (--width);
+}
+
+/* only trivial mods from yuv2rgb_c_24_rgb */
+static void yuv2rgb_c_24_bgr (yuv2rgb_t *this,
+ uint8_t * py_1, uint8_t * py_2,
+ uint8_t * pu, uint8_t * pv,
+ void * _dst_1, void * _dst_2, int width)
+{
+ int U, V, Y;
+ uint8_t * r, * g, * b;
+ uint8_t * dst_1, * dst_2;
+
+ width >>= 3;
+ dst_1 = _dst_1;
+ dst_2 = _dst_2;
+
+ do {
+ RGB(0);
+ DST1BGR(0);
+ DST2BGR(0);
+
+ RGB(1);
+ DST2BGR(1);
+ DST1BGR(1);
+
+ RGB(2);
+ DST1BGR(2);
+ DST2BGR(2);
+
+ RGB(3);
+ DST2BGR(3);
+ DST1BGR(3);
+
+ pu += 4;
+ pv += 4;
+ py_1 += 8;
+ py_2 += 8;
+ dst_1 += 24;
+ dst_2 += 24;
+ } while (--width);
+}
+
+/* This is exactly the same code as yuv2rgb_c_32 except for the types of */
+/* r, g, b, dst_1, dst_2 */
+static void yuv2rgb_c_16 (yuv2rgb_t *this,
+ uint8_t * py_1, uint8_t * py_2,
+ uint8_t * pu, uint8_t * pv,
+ void * _dst_1, void * _dst_2, int width)
+{
+ int U, V, Y;
+ uint16_t * r, * g, * b;
+ uint16_t * dst_1, * dst_2;
+
+ width >>= 3;
+ dst_1 = _dst_1;
+ dst_2 = _dst_2;
+
+ do {
+ RGB(0);
+ DST1(0);
+ DST2(0);
+
+ RGB(1);
+ DST2(1);
+ DST1(1);
+
+ RGB(2);
+ DST1(2);
+ DST2(2);
+
+ RGB(3);
+ DST2(3);
+ DST1(3);
+
+ pu += 4;
+ pv += 4;
+ py_1 += 8;
+ py_2 += 8;
+ dst_1 += 8;
+ dst_2 += 8;
+ } while (--width);
+}
+
+static int div_round (int dividend, int divisor)
+{
+ if (dividend > 0)
+ return (dividend + (divisor>>1)) / divisor;
+ else
+ return -((-dividend + (divisor>>1)) / divisor);
+}
+
+static void yuv2rgb_c_init (yuv2rgb_t *this, int mode)
+{
+ int i;
+ uint8_t table_Y[1024];
+ uint32_t * table_32 = 0;
+ uint16_t * table_16 = 0;
+ uint8_t * table_8 = 0;
+ int entry_size = 0;
+ void *table_r = 0, *table_g = 0, *table_b = 0;
+
+ int crv = Inverse_Table_6_9[this->matrix_coefficients][0];
+ int cbu = Inverse_Table_6_9[this->matrix_coefficients][1];
+ int cgu = -Inverse_Table_6_9[this->matrix_coefficients][2];
+ int cgv = -Inverse_Table_6_9[this->matrix_coefficients][3];
+
+ this->yuv2rgb_fun = yuv2rgb_c;
+
+ for (i = 0; i < 1024; i++) {
+ int j;
+
+ j = (76309 * (i - 384 - 16) + 32768) >> 16;
+ j = (j < 0) ? 0 : ((j > 255) ? 255 : j);
+ table_Y[i] = j;
+ }
+
+ switch (mode) {
+ case MODE_32_RGB:
+ case MODE_32_BGR:
+ this->yuv2rgb_c_internal = yuv2rgb_c_32;
+
+ table_32 = malloc ((197 + 2*682 + 256 + 132) * sizeof (uint32_t));
+
+ entry_size = sizeof (uint32_t);
+ table_r = table_32 + 197;
+ table_b = table_32 + 197 + 685;
+ table_g = table_32 + 197 + 2*682;
+
+ for (i = -197; i < 256+197; i++)
+ ((uint32_t *) table_r)[i] =
+ table_Y[i+384] << ((mode==MODE_32_RGB) ? 16 : 0);
+ for (i = -132; i < 256+132; i++)
+ ((uint32_t *) table_g)[i] = table_Y[i+384] << 8;
+ for (i = -232; i < 256+232; i++)
+ ((uint32_t *) table_b)[i] =
+ table_Y[i+384] << ((mode==MODE_32_RGB) ? 0 : 16);
+ break;
+
+ case MODE_24_RGB:
+ case MODE_24_BGR:
+ this->yuv2rgb_c_internal = (mode==MODE_24_RGB) ? yuv2rgb_c_24_rgb : yuv2rgb_c_24_bgr;
+
+ table_8 = malloc ((256 + 2*232) * sizeof (uint8_t));
+
+ entry_size = sizeof (uint8_t);
+ table_r = table_g = table_b = table_8 + 232;
+
+ for (i = -232; i < 256+232; i++)
+ ((uint8_t * )table_b)[i] = table_Y[i+384];
+ break;
+
+ case MODE_15_BGR:
+ case MODE_16_BGR:
+ case MODE_15_RGB:
+ case MODE_16_RGB:
+ this->yuv2rgb_c_internal = yuv2rgb_c_16;
+
+ table_16 = malloc ((197 + 2*682 + 256 + 132) * sizeof (uint16_t));
+
+ entry_size = sizeof (uint16_t);
+ table_r = table_16 + 197;
+ table_b = table_16 + 197 + 685;
+ table_g = table_16 + 197 + 2*682;
+
+ for (i = -197; i < 256+197; i++) {
+ int j = table_Y[i+384] >> 3;
+
+ if (mode == MODE_16_RGB)
+ j <<= 11;
+ else if (mode == MODE_15_RGB)
+ j <<= 10;
+
+ ((uint16_t *)table_r)[i] = j;
+ }
+ for (i = -132; i < 256+132; i++) {
+ int j = table_Y[i+384] >> (((mode==MODE_16_RGB) || (mode==MODE_16_BGR)) ? 2 : 3);
+
+ ((uint16_t *)table_g)[i] = j << 5;
+ }
+ for (i = -232; i < 256+232; i++) {
+ int j = table_Y[i+384] >> 3;
+
+ if (mode == MODE_16_BGR)
+ j <<= 11;
+ if (mode == MODE_15_BGR)
+ j <<= 10;
+
+ ((uint16_t *)table_b)[i] = j;
+ }
+ break;
+
+ default:
+ fprintf (stderr, "mode %d not supported by yuv2rgb\n", mode);
+ exit (1);
+ }
+
+ for (i = 0; i < 256; i++) {
+ this->table_rV[i] = (((uint8_t *) table_r) +
+ entry_size * div_round (crv * (i-128), 76309));
+ this->table_gU[i] = (((uint8_t *) table_g) +
+ entry_size * div_round (cgu * (i-128), 76309));
+ this->table_gV[i] = entry_size * div_round (cgv * (i-128), 76309);
+ this->table_bU[i] = (((uint8_t *)table_b) +
+ entry_size * div_round (cbu * (i-128), 76309));
+ }
+}
+
+yuv2rgb_t *yuv2rgb_init (int mode) {
+
+ uint32_t mm = mm_accel();
+ yuv2rgb_t *this = xmalloc (sizeof (yuv2rgb_t));
+
+
+ this->matrix_coefficients = 6;
+
+ this->y_buffer = NULL;
+ this->u_buffer = NULL;
+ this->v_buffer = NULL;
+
+ /*
+ * auto-probe for the best yuv2rgb function
+ */
+
+ this->yuv2rgb_fun = NULL;
+#ifdef ARCH_X86
+ if ((this->yuv2rgb_fun == NULL) && (mm & MM_ACCEL_X86_MMXEXT)) {
+ yuv2rgb_init_mmxext (this, mode);
+ if (this->yuv2rgb_fun != NULL)
+ fprintf (stderr, "Using MMXEXT for colorspace transform\n");
+ }
+ if ((this->yuv2rgb_fun == NULL) && (mm & MM_ACCEL_X86_MMX)) {
+ yuv2rgb_init_mmx (this, mode);
+ if (this->yuv2rgb_fun != NULL)
+ fprintf (stderr, "Using MMX for colorspace transform\n");
+ }
+#endif
+ if (this->yuv2rgb_fun == NULL) {
+ fprintf (stderr, "No accelerated colorspace conversion found\n");
+ yuv2rgb_c_init (this, mode);
+ }
+ return this;
+}
diff --git a/src/video_out/yuv2rgb.h b/src/video_out/yuv2rgb.h
new file mode 100644
index 000000000..51de2ae01
--- /dev/null
+++ b/src/video_out/yuv2rgb.h
@@ -0,0 +1,81 @@
+
+#ifndef HAVE_YUV2RGB_H
+#define HAVE_YUV2RGB_h
+
+#include <inttypes.h>
+
+/*
+ * modes supported - feel free to implement yours
+ */
+
+#define MODE_15_RGB 1
+#define MODE_15_BGR 2
+#define MODE_16_RGB 3
+#define MODE_16_BGR 4
+#define MODE_24_RGB 5
+#define MODE_24_BGR 6
+#define MODE_32_RGB 7
+#define MODE_32_BGR 8
+
+typedef struct yuv2rgb_s yuv2rgb_t;
+
+struct yuv2rgb_s {
+
+ /*
+ * this is the function to call for the yuv2rgb and scaling process
+ */
+ void (*yuv2rgb_fun) (yuv2rgb_t *this, uint8_t * image, uint8_t * py,
+ uint8_t * pu, uint8_t * pv) ;
+
+ /* private stuff below */
+
+ uint32_t matrix_coefficients;
+ int source_width, source_height;
+ int y_stride, uv_stride;
+ int dest_width, dest_height;
+ int rgb_stride;
+ int step_dx, step_dy;
+ int do_scale;
+ uint8_t *y_buffer;
+ uint8_t *u_buffer;
+ uint8_t *v_buffer;
+
+ void *table_rV[256];
+ void *table_gU[256];
+ int table_gV[256];
+ void *table_bU[256];
+
+ void (* yuv2rgb_c_internal) (yuv2rgb_t *this,
+ uint8_t *, uint8_t *,
+ uint8_t *, uint8_t *,
+ void *, void *, int);
+} ;
+
+
+/* call once on startup */
+yuv2rgb_t *yuv2rgb_init (int mode);
+
+/*
+ * set up yuv2rgb function, determine scaling parameters if necessary
+ * returns 0 on failure, 1 otherwise
+ */
+int yuv2rgb_setup (yuv2rgb_t *this,
+ int source_width, int source_height,
+ int y_stride, int uv_stride,
+ int dest_width, int dest_height,
+ int rgb_stride);
+
+/*
+ * internal stuff below this line
+ */
+
+void yuv2rgb_init_mmxext (yuv2rgb_t *this, int mode);
+void yuv2rgb_init_mmx (yuv2rgb_t *this, int mode);
+
+/*
+void Color565DitherYV12MMX1X(unsigned char *lum, unsigned char *cr,
+ unsigned char *cb, unsigned char *out,
+ int rows, int cols, int mod );
+*/
+
+#endif
diff --git a/src/video_out/yuv2rgb_mmx.c b/src/video_out/yuv2rgb_mmx.c
new file mode 100644
index 000000000..8ab3b050d
--- /dev/null
+++ b/src/video_out/yuv2rgb_mmx.c
@@ -0,0 +1,537 @@
+/*
+ * yuv2rgb_mmx.c
+ * Copyright (C) 2000-2001 Silicon Integrated System Corp.
+ * All Rights Reserved.
+ *
+ * Author: Olie Lho <ollie@sis.com.tw>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ *
+ * mpeg2dec is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mpeg2dec is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+
+#ifdef ARCH_X86
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include "attributes.h"
+#include "cpu_accel.h"
+#include "yuv2rgb.h"
+
+#define CPU_MMXEXT 0
+#define CPU_MMX 1
+
+/* CPU_MMXEXT/CPU_MMX adaptation layer */
+
+#define movntq(src,dest) \
+do { \
+ if (cpu == CPU_MMXEXT) \
+ movntq_r2m (src, dest); \
+ else \
+ movq_r2m (src, dest); \
+} while (0)
+
+static inline void mmx_yuv2rgb (uint8_t * py, uint8_t * pu, uint8_t * pv)
+{
+ static mmx_t mmx_80w = {0x0080008000800080};
+ static mmx_t mmx_U_green = {0xf37df37df37df37d};
+ static mmx_t mmx_U_blue = {0x4093409340934093};
+ static mmx_t mmx_V_red = {0x3312331233123312};
+ static mmx_t mmx_V_green = {0xe5fce5fce5fce5fc};
+ static mmx_t mmx_10w = {0x1010101010101010};
+ static mmx_t mmx_00ffw = {0x00ff00ff00ff00ff};
+ static mmx_t mmx_Y_coeff = {0x253f253f253f253f};
+
+ movq_m2r (*py, mm6); // mm6 = Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
+ pxor_r2r (mm4, mm4); // mm4 = 0
+
+ psubusb_m2r (mmx_10w, mm6); // Y -= 16
+
+
+ movd_m2r (*pu, mm0); // mm0 = 00 00 00 00 u3 u2 u1 u0
+ movq_r2r (mm6, mm7); // mm7 = Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
+
+ pand_m2r (mmx_00ffw, mm6); // mm6 = Y6 Y4 Y2 Y0
+ psrlw_i2r (8, mm7); // mm7 = Y7 Y5 Y3 Y1
+
+ movd_m2r (*pv, mm1); // mm1 = 00 00 00 00 v3 v2 v1 v0
+ psllw_i2r (3, mm6); // promote precision
+
+ pmulhw_m2r (mmx_Y_coeff, mm6); // mm6 = luma_rgb even
+ psllw_i2r (3, mm7); // promote precision
+
+ punpcklbw_r2r (mm4, mm0); // mm0 = u3 u2 u1 u0
+
+ psubsw_m2r (mmx_80w, mm0); // u -= 128
+ punpcklbw_r2r (mm4, mm1); // mm1 = v3 v2 v1 v0
+
+ pmulhw_m2r (mmx_Y_coeff, mm7); // mm7 = luma_rgb odd
+ psllw_i2r (3, mm0); // promote precision
+
+ psubsw_m2r (mmx_80w, mm1); // v -= 128
+ movq_r2r (mm0, mm2); // mm2 = u3 u2 u1 u0
+
+ psllw_i2r (3, mm1); // promote precision
+
+ movq_r2r (mm1, mm4); // mm4 = v3 v2 v1 v0
+
+ pmulhw_m2r (mmx_U_blue, mm0); // mm0 = chroma_b
+
+
+ // slot
+
+
+ // slot
+
+
+ pmulhw_m2r (mmx_V_red, mm1); // mm1 = chroma_r
+ movq_r2r (mm0, mm3); // mm3 = chroma_b
+
+ paddsw_r2r (mm6, mm0); // mm0 = B6 B4 B2 B0
+ paddsw_r2r (mm7, mm3); // mm3 = B7 B5 B3 B1
+
+ packuswb_r2r (mm0, mm0); // saturate to 0-255
+
+
+ pmulhw_m2r (mmx_U_green, mm2); // mm2 = u * u_green
+
+
+ packuswb_r2r (mm3, mm3); // saturate to 0-255
+
+
+ punpcklbw_r2r (mm3, mm0); // mm0 = B7 B6 B5 B4 B3 B2 B1 B0
+
+
+ pmulhw_m2r (mmx_V_green, mm4); // mm4 = v * v_green
+
+
+ // slot
+
+
+ // slot
+
+
+ paddsw_r2r (mm4, mm2); // mm2 = chroma_g
+ movq_r2r (mm2, mm5); // mm5 = chroma_g
+
+
+ movq_r2r (mm1, mm4); // mm4 = chroma_r
+ paddsw_r2r (mm6, mm2); // mm2 = G6 G4 G2 G0
+
+
+ packuswb_r2r (mm2, mm2); // saturate to 0-255
+ paddsw_r2r (mm6, mm1); // mm1 = R6 R4 R2 R0
+
+ packuswb_r2r (mm1, mm1); // saturate to 0-255
+ paddsw_r2r (mm7, mm4); // mm4 = R7 R5 R3 R1
+
+ packuswb_r2r (mm4, mm4); // saturate to 0-255
+ paddsw_r2r (mm7, mm5); // mm5 = G7 G5 G3 G1
+
+
+ packuswb_r2r (mm5, mm5); // saturate to 0-255
+
+
+ punpcklbw_r2r (mm4, mm1); // mm1 = R7 R6 R5 R4 R3 R2 R1 R0
+
+
+ punpcklbw_r2r (mm5, mm2); // mm2 = G7 G6 G5 G4 G3 G2 G1 G0
+}
+
+// basic opt
+static inline void mmx_unpack_16rgb (uint8_t * image, int cpu)
+{
+ static mmx_t mmx_bluemask = {0xf8f8f8f8f8f8f8f8};
+ static mmx_t mmx_greenmask = {0xfcfcfcfcfcfcfcfc};
+ static mmx_t mmx_redmask = {0xf8f8f8f8f8f8f8f8};
+
+ /*
+ * convert RGB plane to RGB 16 bits
+ * mm0 -> B, mm1 -> R, mm2 -> G
+ * mm4 -> GB, mm5 -> AR pixel 4-7
+ * mm6 -> GB, mm7 -> AR pixel 0-3
+ */
+
+ pand_m2r (mmx_bluemask, mm0); // mm0 = b7b6b5b4b3______
+ pxor_r2r (mm4, mm4); // mm4 = 0
+
+ pand_m2r (mmx_greenmask, mm2); // mm2 = g7g6g5g4g3g2____
+ psrlq_i2r (3, mm0); // mm0 = ______b7b6b5b4b3
+
+ movq_r2r (mm2, mm7); // mm7 = g7g6g5g4g3g2____
+ movq_r2r (mm0, mm5); // mm5 = ______b7b6b5b4b3
+
+ pand_m2r (mmx_redmask, mm1); // mm1 = r7r6r5r4r3______
+ punpcklbw_r2r (mm4, mm2);
+
+ punpcklbw_r2r (mm1, mm0);
+
+ psllq_i2r (3, mm2);
+
+ punpckhbw_r2r (mm4, mm7);
+ por_r2r (mm2, mm0);
+
+ psllq_i2r (3, mm7);
+
+ movntq (mm0, *image);
+ punpckhbw_r2r (mm1, mm5);
+
+ por_r2r (mm7, mm5);
+
+ // U
+ // V
+
+ movntq (mm5, *(image+8));
+}
+
+static inline void mmx_unpack_32rgb (uint8_t * image, int cpu)
+{
+ /*
+ * convert RGB plane to RGB packed format,
+ * mm0 -> B, mm1 -> R, mm2 -> G, mm3 -> 0,
+ * mm4 -> GB, mm5 -> AR pixel 4-7,
+ * mm6 -> GB, mm7 -> AR pixel 0-3
+ */
+
+ pxor_r2r (mm3, mm3);
+ movq_r2r (mm0, mm6);
+
+ punpcklbw_r2r (mm2, mm6);
+ movq_r2r (mm1, mm7);
+
+ punpcklbw_r2r (mm3, mm7);
+ movq_r2r (mm0, mm4);
+
+ punpcklwd_r2r (mm7, mm6);
+ movq_r2r (mm1, mm5);
+
+ /* scheduling: this is hopeless */
+ movntq (mm6, *image);
+ movq_r2r (mm0, mm6);
+ punpcklbw_r2r (mm2, mm6);
+ punpckhwd_r2r (mm7, mm6);
+ movntq (mm6, *(image+8));
+ punpckhbw_r2r (mm2, mm4);
+ punpckhbw_r2r (mm3, mm5);
+ punpcklwd_r2r (mm5, mm4);
+ movntq (mm4, *(image+16));
+ movq_r2r (mm0, mm4);
+ punpckhbw_r2r (mm2, mm4);
+ punpckhwd_r2r (mm5, mm4);
+ movntq (mm4, *(image+24));
+}
+
+static inline void mmx_unpack_24rgb (uint8_t * image, int cpu)
+{
+ /*
+ * convert RGB plane to RGB packed format,
+ * mm0 -> B, mm1 -> R, mm2 -> G, mm3 -> 0,
+ * mm4 -> GB, mm5 -> AR pixel 4-7,
+ * mm6 -> GB, mm7 -> AR pixel 0-3
+ */
+
+ pxor_r2r (mm3, mm3);
+ movq_r2r (mm0, mm6);
+
+ punpcklbw_r2r (mm2, mm6);
+ movq_r2r (mm1, mm7);
+
+ punpcklbw_r2r (mm3, mm7);
+ movq_r2r (mm0, mm4);
+
+ punpcklwd_r2r (mm7, mm6);
+ movq_r2r (mm1, mm5);
+
+ /* scheduling: this is hopeless */
+ movntq (mm6, *image);
+ movq_r2r (mm0, mm6);
+ punpcklbw_r2r (mm2, mm6);
+ punpckhwd_r2r (mm7, mm6);
+ movntq (mm6, *(image+8));
+ punpckhbw_r2r (mm2, mm4);
+ punpckhbw_r2r (mm3, mm5);
+ punpcklwd_r2r (mm5, mm4);
+ movntq (mm4, *(image+16));
+}
+
+static void scale_line (uint8_t *source, uint8_t *dest,
+ int width, int step) {
+
+ int p1;
+ int p2;
+ int dx;
+
+ p1 = *source++;
+ p2 = *source++;
+ dx = 0;
+
+ while (width) {
+
+ /*
+ printf ("scale_line, width = %d\n", width);
+ printf ("scale_line, dx = %d, p1 = %d, p2 = %d\n", dx, p1, p2);
+ */
+
+ *dest = (p1 * (32768 - dx) + p2 * dx) / 32768;
+
+ dx += step;
+ while (dx > 32768) {
+ dx -= 32768;
+ p1 = p2;
+ p2 = *source++;
+ }
+
+ dest ++;
+ width --;
+ }
+
+}
+
+
+static inline void yuv420_rgb16 (yuv2rgb_t *this,
+ uint8_t * image,
+ uint8_t * py, uint8_t * pu, uint8_t * pv,
+ int cpu)
+{
+ int i;
+ int rgb_stride = this->rgb_stride;
+ int y_stride = this->y_stride;
+ int uv_stride = this->uv_stride;
+ int width = this->source_width;
+ int height = this->source_height;
+
+ rgb_stride -= 2 * this->dest_width;
+ width >>= 3;
+
+ if (!this->do_scale) {
+ y_stride -= width;
+ uv_stride -= width >> 1;
+
+ do {
+
+ i = width;
+ do {
+ mmx_yuv2rgb (py, pu, pv);
+ mmx_unpack_16rgb (image, cpu);
+ py += 8;
+ pu += 4;
+ pv += 4;
+ image += 16;
+ } while (--i);
+
+ py += y_stride;
+ image += rgb_stride;
+ if (height & 1) {
+ pu += uv_stride;
+ pv += uv_stride;
+ } else {
+ pu -= 4 * width;
+ pv -= 4 * width;
+ }
+ } while (--height);
+
+ } else {
+
+ uint8_t *y_buf, *u_buf, *v_buf;
+
+ scale_line (pu, this->u_buffer,
+ this->dest_width >> 1, this->step_dx);
+ scale_line (pv, this->v_buffer,
+ this->dest_width >> 1, this->step_dx);
+
+ do {
+
+ y_buf = this->y_buffer;
+ u_buf = this->u_buffer;
+ v_buf = this->v_buffer;
+
+ scale_line (py, y_buf,
+ this->dest_width, this->step_dx);
+
+
+ i = this->dest_width >> 3;
+ do {
+ /* printf ("i : %d\n",i); */
+
+ mmx_yuv2rgb (y_buf, u_buf, v_buf);
+ mmx_unpack_16rgb (image, cpu);
+ y_buf += 8;
+ u_buf += 4;
+ v_buf += 4;
+ image += 16;
+ } while (--i);
+
+ py += y_stride;
+ image += rgb_stride;
+
+ if (height & 1) {
+ pu += uv_stride;
+ pv += uv_stride;
+
+ scale_line (pu, this->u_buffer,
+ this->dest_width >> 1, this->step_dx);
+ scale_line (pv, this->v_buffer,
+ this->dest_width >> 1, this->step_dx);
+
+ }
+
+ } while (--height);
+ }
+}
+
+static inline void yuv420_argb32 (yuv2rgb_t *this,
+ uint8_t * image, uint8_t * py,
+ uint8_t * pu, uint8_t * pv, int cpu)
+{
+ int i;
+ int rgb_stride = this->rgb_stride;
+ int y_stride = this->y_stride;
+ int uv_stride = this->uv_stride;
+ int width = this->source_width;
+ int height = this->source_height;
+
+ rgb_stride -= 4 * this->dest_width;
+ width >>= 3;
+
+ if (!this->do_scale) {
+ y_stride -= width;
+ uv_stride -= width >> 1;
+
+ do {
+ i = width;
+ do {
+ mmx_yuv2rgb (py, pu, pv);
+ mmx_unpack_32rgb (image, cpu);
+ py += 8;
+ pu += 4;
+ pv += 4;
+ image += 32;
+ } while (--i);
+
+ py += y_stride;
+ image += rgb_stride;
+ if (height & 1) {
+ pu += uv_stride;
+ pv += uv_stride;
+ } else {
+ pu -= 4 * width;
+ pv -= 4 * width;
+ }
+ } while (--height);
+ } else {
+ uint8_t *y_buf, *u_buf, *v_buf;
+
+ scale_line (pu, this->u_buffer,
+ this->dest_width >> 1, this->step_dx);
+ scale_line (pv, this->v_buffer,
+ this->dest_width >> 1, this->step_dx);
+
+ do {
+
+ y_buf = this->y_buffer;
+ u_buf = this->u_buffer;
+ v_buf = this->v_buffer;
+
+ scale_line (py, y_buf,
+ this->dest_width, this->step_dx);
+
+
+ i = this->dest_width >> 3;
+ do {
+ /* printf ("i : %d\n",i); */
+
+ mmx_yuv2rgb (y_buf, u_buf, v_buf);
+ mmx_unpack_32rgb (image, cpu);
+ y_buf += 8;
+ u_buf += 4;
+ v_buf += 4;
+ image += 32;
+ } while (--i);
+
+ py += y_stride;
+ image += rgb_stride;
+
+ if (height & 1) {
+ pu += uv_stride;
+ pv += uv_stride;
+
+ scale_line (pu, this->u_buffer,
+ this->dest_width >> 1, this->step_dx);
+ scale_line (pv, this->v_buffer,
+ this->dest_width >> 1, this->step_dx);
+
+ }
+
+ } while (--height);
+
+ }
+}
+
+static void mmxext_rgb16 (yuv2rgb_t *this, uint8_t * image,
+ uint8_t * py, uint8_t * pu, uint8_t * pv)
+{
+ yuv420_rgb16 (this, image, py, pu, pv, CPU_MMXEXT);
+}
+
+static void mmxext_argb32 (yuv2rgb_t *this, uint8_t * image,
+ uint8_t * py, uint8_t * pu, uint8_t * pv)
+{
+ yuv420_argb32 (this, image, py, pu, pv, CPU_MMXEXT);
+}
+
+static void mmx_rgb16 (yuv2rgb_t *this, uint8_t * image,
+ uint8_t * py, uint8_t * pu, uint8_t * pv)
+{
+ yuv420_rgb16 (this, image, py, pu, pv, CPU_MMX);
+}
+
+static void mmx_argb32 (yuv2rgb_t *this, uint8_t * image,
+ uint8_t * py, uint8_t * pu, uint8_t * pv)
+{
+ yuv420_argb32 (this, image, py, pu, pv, CPU_MMX);
+}
+
+void yuv2rgb_init_mmxext (yuv2rgb_t *this, int mode)
+{
+ switch (mode) {
+ case MODE_16_RGB:
+ this->yuv2rgb_fun = mmxext_rgb16;
+ break;
+ case MODE_32_RGB:
+ this->yuv2rgb_fun = mmxext_argb32;
+ break;
+ }
+}
+
+void yuv2rgb_init_mmx (yuv2rgb_t *this, int mode)
+{
+ switch (mode) {
+ case MODE_16_RGB:
+ this->yuv2rgb_fun = mmx_rgb16;
+ break;
+ case MODE_32_RGB:
+ this->yuv2rgb_fun = mmx_argb32;
+ break;
+ }
+}
+
+
+#endif
+
+
diff --git a/src/xine-engine/Makefile.am b/src/xine-engine/Makefile.am
index a58623dce..ef533c055 100644
--- a/src/xine-engine/Makefile.am
+++ b/src/xine-engine/Makefile.am
@@ -7,9 +7,11 @@ CFLAGS = @GLOBAL_CFLAGS@
lib_LTLIBRARIES = libxine.la
##libxine_la_SOURCES = xine.c buffer.c metronom.c configfile.c \
-## monitor.c utils.c audio_decoder.c video_decoder.c load_plugins.c
-libxine_la_SOURCES = metronom.c configfile.c buffer.c monitor.c utils.c cpu_accel.c \
- load_plugins.c video_decoder.c audio_decoder.c
+## monitor.c utils.c audio_decoder.c video_decoder.c load_plugins.c \
+## audio_out.c
+libxine_la_SOURCES = metronom.c configfile.c buffer.c monitor.c utils.c \
+ cpu_accel.c load_plugins.c video_decoder.c audio_decoder.c \
+ video_out.c
libxine_la_DEPENDENCIES = libsdeps
libxine_la_LIBADD = \
## $(top_srcdir)/src/libmpeg2/libmpeg2.la \
@@ -25,6 +27,7 @@ libxine_la_LDFLAGS = -version-info 5:0:5
# monitor.h cpu_accel.h attributes.h utils.h audio_decoder.h
noinst_HEADERS = xine_internal.h buffer.h metronom.h configfile.h \
monitor.h cpu_accel.h attributes.h utils.h
+include_HEADERS = audio_out.h video_out.h
###
# Hardcoded rule:
diff --git a/include/audio_out.h b/src/xine-engine/audio_out.h
index 3e0118325..5688645b2 100644
--- a/include/audio_out.h
+++ b/src/xine-engine/audio_out.h
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: audio_out.h,v 1.1 2001/04/18 22:36:42 f1rmb Exp $
+ * $Id: audio_out.h,v 1.1 2001/04/24 20:53:00 f1rmb Exp $
*/
#ifndef HAVE_AUDIO_OUT_H
#define HAVE_AUDIO_OUT_H
diff --git a/include/video_out.h b/src/xine-engine/video_out.h
index 8e733bde2..a6ed08231 100644
--- a/include/video_out.h
+++ b/src/xine-engine/video_out.h
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: video_out.h,v 1.6 2001/04/23 22:43:59 f1rmb Exp $
+ * $Id: video_out.h,v 1.1 2001/04/24 20:53:00 f1rmb Exp $
*
*
* xine version of video_out.h